关于bash:为什么正确的shell脚本会给出包装/截断/损坏的错误消息?

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

本问题已经有最佳答案,请猛点这里访问。

我有一个带有命令的shell脚本,它看起来应该可以正常工作,但是它会因奇怪的包装/截断/损坏错误消息而失败。 例:

1
2
3
4
5
6
$ 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

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

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

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

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

1
2
3
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命令应该工作,或者至少给出一个正常的错误信息,但是它被包裹起来以冒号开头并以奇怪的破坏结束:

1
2
3
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样式。

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

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

1
2
$ cat -v myscript
ls -l myfile^M

如果您的脚本没有它们,您的数据可能会 - 尤其是从ini / csv文件或curl读取时:

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

我该如何删除它们?

将编辑器设置为使用Unix行结尾保存文件,即"行终止符"或"行尾字符",然后重新保存。

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

如果在您的数据中找到,您可以通过tr -d '
'
管道来源:

1
2
hostname=$(curl https://example.com/loginhost.txt | tr -d '
'
)

为什么回车导致奇怪的错误信息?

"回车"字符,即CR或
,使光标移动到行的开头,并从那里继续打印。换句话说,它从头开始覆盖该行。这就是他们奇怪地包裹的原因:

1
2
3
4
5
6
7
Intended:     ssh: Could not resolve hostname myhost
: Name or service not known

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