在 Linux 中像 MSYS2 一样处理带有 CRLF(回车符)的 Bash 脚本?

sda*_*aau 9 linux bash msys newlines

假设我有以下简单的脚本tmp.sh

\n\n
echo "testing"\nstat .\necho "testing again"\n
Run Code Online (Sandbox Code Playgroud)\n\n

尽管它很简单,但它以\\r\\n(即 CRLF,即回车+换行)作为行结尾。由于网页不会保留行结尾,因此这里是一个十六进制转储:

\n\n
$ hexdump -C tmp.sh \n00000000  65 63 68 6f 20 22 74 65  73 74 69 6e 67 22 0d 0a  |echo "testing"..|\n00000010  73 74 61 74 20 2e 0d 0a  65 63 68 6f 20 22 74 65  |stat ...echo "te|\n00000020  73 74 69 6e 67 20 61 67  61 69 6e 22 0d 0a        |sting again"..|\n0000002e\n
Run Code Online (Sandbox Code Playgroud)\n\n

现在,它具有 CRLF 行结尾,因为该脚本是在 Windows 上的 MSYS2 下启动和开发的。因此,当我在 Windows 10 上的 MSYS2 中运行它时,我得到了预期的结果:

\n\n
$ bash tmp.sh\ntesting\n  File: .\n  Size: 0               Blocks: 40         IO Block: 65536  directory\nDevice: 8e8b98b6h/2391513270d   Inode: 281474976761067  Links: 1\nAccess: (0755/drwxr-xr-x)  Uid: (197609/      USER)   Gid: (197121/    None)\nAccess: 2020-04-03 10:42:53.210292000 +0200\nModify: 2020-04-03 10:42:53.210292000 +0200\nChange: 2020-04-03 10:42:53.210292000 +0200\n Birth: 2019-02-07 13:22:11.496069300 +0100\ntesting again\n
Run Code Online (Sandbox Code Playgroud)\n\n

但是,如果我将此脚本复制到 Ubuntu 18.04 计算机并在那里运行它,我会得到其他内容:

\n\n
$ bash tmp.sh\ntesting\nstat: cannot stat \'.\'$\'\\r\': No such file or directory\ntesting again\n
Run Code Online (Sandbox Code Playgroud)\n\n

在具有相同行结尾的其他脚本中,我在 Ubuntu bash 中也遇到了此错误:

\n\n
line 6: $\'\\r\': command not found\n
Run Code Online (Sandbox Code Playgroud)\n\n

...可能来自空行。

\n\n

所以,很明显,Ubuntu 中的某些东西在回车时会被卡住。我见过BASH 和回车行为

\n\n
\n

它与 Bash 没有任何关系: \\r 和 \\n 由终端解释,而不是由 Bash 解释

\n
\n\n

...但是,我想这仅适用于在命令行上逐字输入的内容;这里的\\r\\n已经在脚本本身中输入了,所以 Bash 一定会解释这里\\r的。

\n\n

这是 Ubuntu 中 Bash 的版本:

\n\n
$ bash --version\nGNU bash, version 4.4.20(1)-release (x86_64-pc-linux-gnu)\n
Run Code Online (Sandbox Code Playgroud)\n\n

...这里是 MSYS2 中的 Bash 版本:

\n\n
$ bash --version\nGNU bash, version 4.4.23(2)-release (x86_64-pc-msys)\n
Run Code Online (Sandbox Code Playgroud)\n\n

(他们看起来并没有那么遥远......)

\n\n

无论如何,我的问题是 - 有没有办法说服 Ubuntu/Linux 上的 Bash 忽略\\r,而不是试图将其解释为(可以这么说)“可打印字符”(在本例中,意味着一个可能是有效命令的一部分,bash 如此解释)?编辑:无需转换脚本本身(因此它保持不变,带有 CRLF 行结尾,如果以这种方式检查,例如在 git 中)

\n\n

EDIT2:我更喜欢这种方式,因为与我一起工作的其他人可能会在 Windows 文本编辑器中重新打开脚本,可能会\\r\\n再次重新引入脚本并提交它;然后我们可能会得到无休止的提交流,这可能只不过是污染存储库的\\r\\n转换\\n

\n\n

编辑2:@Kusalananda 在评论中提到dos2unixsudo apt install dos2unix);请注意,只需这样写:

\n\n
$ dos2unix tmp.sh \ndos2unix: converting file tmp.sh to Unix format...\n
Run Code Online (Sandbox Code Playgroud)\n\n

...将就地转换文件;要将其输出到 stdout,必须设置 stdin 重定向:

\n\n
$ dos2unix <tmp.sh | hexdump -C\n00000000  65 63 68 6f 20 22 74 65  73 74 69 6e 67 22 0a 73  |echo "testing".s|\n00000010  74 61 74 20 2e 0a 65 63  68 6f 20 22 74 65 73 74  |tat ..echo "test|\n00000020  69 6e 67 20 61 67 61 69  6e 22 0a                 |ing again".|\n0000002b\n
Run Code Online (Sandbox Code Playgroud)\n\n

...然后,原则上,可以在 Ubuntu 上运行它,这似乎在这种情况下有效:

\n\n
$ dos2unix <tmp.sh | bash\ntesting\n  File: .\n  Size: 20480       Blocks: 40         IO Block: 4096   directory\nDevice: 816h/2070d  Inode: 1572865     Links: 27\nAccess: (1777/drwxrwxrwt)  Uid: (    0/    root)   Gid: (    0/    root)\nAccess: 2020-04-03 11:11:00.309160050 +0200\nModify: 2020-04-03 11:10:58.349139481 +0200\nChange: 2020-04-03 11:10:58.349139481 +0200\n Birth: -\ntesting again\n
Run Code Online (Sandbox Code Playgroud)\n\n

然而,除了需要记住的稍微混乱的命令之外,这也改变了 bash 语义,因为 stdin 不再是终端;这可能适用于这个简单的示例,但请参阅/sf/ask/1628007321/作为更大问题的示例。

\n

Ste*_*itt 6

据我所知,xe2x80x99m 没有办法告诉 Bash 接受 Windows 风格的行结尾。

\n\n

在涉及 Windows 的情况下,常见的做法是依靠 Git\xe2\x80\x99s 在提交时使用autocrlf配置标志自动转换行结束符的能力。例如,请参阅有关行结尾的 GitHub\xe2\x80\x99s 文档,该文档不是 GitHub 特有的\xe2\x80\x99s。这样,文件就会在存储库中以 Unix 风格的行结尾提交,并根据每个客户端平台进行适当的转换。

\n\n

(相反的问题是 \xe2\x80\x99t 问题:MSYS2 在 Windows 上可以很好地处理 Unix 风格的行结尾。)

\n