为什么正确的 shell 脚本会给出 wrapped/truncated/corrupted 错误消息?

Why would a correct shell script give a wrapped/truncated/corrupted error message?

我有一个 shell 脚本,其中的命令似乎应该有效,但它却失败了,并显示了一条奇怪的 wrapped/truncated/corrupted 错误消息。示例:

$ ls -l myfile
-rw-r----- 1 me me 0 Aug  7 12:36 myfile
$ cat myscript 
ls -l myfile
$ bash myscript
: No such file or directory

文件显然存在,但即使我不存在,这也是我通常会收到的错误消息:

$ ls -l idontexist
ls: cannot access idontexist: No such file or directory

注意它是如何包含工具名称 ls、消息字符串和文件名的,而我的没有。

这是我尝试使用 mysql 时得到的结果。错误消息看起来已被包装,现在以引号开头:

Command:  mysql -h myhost.example.com
Expected: ERROR 2005 (HY000): Unknown MySQL server host 'myhost.example.com' (0)
Actual:   ' (0) 2005 (HY000): Unknown MySQL server host 'myhost.example.com

这是我的简单 ssh 命令,它应该可以工作,或者至少给出一个正常的错误消息,但它被包装成以冒号开头并以奇怪的破坏结尾:

Command:  ssh myhost
Expected: ssh: Could not resolve hostname myhost: Name or service not known
Actual:   : Name or service not knownname myhost

为什么会发生这种情况,我该如何解决?

TL;DR:您的脚本或数据具有 Windows 样式的 CRLF 行结尾。

通过删除回车符转换为 Unix 风格 returns。


如何检查我的脚本或数据是否有回车 returns?

它们在 cat -v yourscript 的输出中被检测为 ^M:

$ cat -v myscript
ls -l myfile^M

如果您的脚本没有它们,您的数据可能 -- 特别是如果从 ini/csv 文件或 curl:

读取
hostname=$(curl https://example.com/loginhost.txt)
ssh "$hostname"            # Shows strange error
echo "$hostname" | cat -v  # Shows myhost^M

如何删除它们?

将您的编辑器设置为使用 Unix 行结尾保存文件,即 "line terminators" 或 "end-of-line characters",然后重新保存。

您也可以使用 dos2unix yourscriptcat yourscript | tr -d '\r' > fixedscript 从命令行删除它们。

如果在您的数据中找到,您可以通过 tr -d '\r':

管道传输您的来源
hostname=$(curl https://example.com/loginhost.txt | tr -d '\r')

为什么回车 returns 会导致出现奇怪的错误消息?

"carriage return" 字符,又名 CR 或 \r,使光标移动到行的开头,并从那里继续打印。换句话说,它从头开始覆盖该行。这就是为什么他们奇怪地包装:

Intended:     ssh: Could not resolve hostname myhost\r: Name or service not known

Written:      ssh: Could not resolve hostname myhost\r
Overwritten:  : Name or service not known
              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^                  
Result:       : Name or service not knownname myhost