初学写 Bash 脚本的同学可能会好奇为什么大家都说不可以用微软 Windows 操作系统自带的记事本编写脚本。有心尝试的同学可能已经知道,用记事本写出的脚本 Bash 很可能会报错,那么?这是为什么呢?
我们先从实做开始,那么就先启动 Windows 操作系统吧。打开 Windows 记事本,加入以下几行:
Default
#! /bin/bash
# This is a script written in Windows Notepad which serves as a test for redundant carriage return characters.
echo "This is the first line \
of the script."
echo "This is the second \
line of the script."
1
2
3
4
5
6
7
8
#! /bin/bash
# This is a script written in Windows Notepad which serves as a test for redundant carriage return characters.
echo"This is the first line \
of the script."
echo"This is the second \
line of the script."
编辑完毕后保存。然后在 Linux 下将这个文件复制到你的 Linux 文件系统上。打开这个文件,你看到的内容可能与之前在 Windows 下编辑的文本文件并无区别。好,先把它放在这里,我们把它叫做 test1。
在 Linux 下,我们使用文本编辑器(如 vi),编辑 test2 文件,加入同样的内容,然后保存。
下面我们分别运行这两个文件(运行前请先行赋予这两个文件以可执行权限)。对于 test2,我们得到如下输出:
Default
$ ./test2
This is the first line of the script.
This is the second line of the script.
1
2
3
$./test2
Thisisthefirstlineofthescript.
Thisisthesecondlineofthescript.
对于 test1,我们则得到这样的输出:
Default
$ ./test1
bash: ./test1: /bin/bash^M: bad interpreter: No such file or directory
1
2
$./test1
bash:./test1:/bin/bash^M:badinterpreter:Nosuchfileordirectory
此时我们知道,在 Windows 下用记事本编写的脚本运行出错了。查看一下报错信息,我们注意到从 header 这一行就已经出错了,header 这一行本来是要告诉我们的内核使用 Bash 这个命令解释器,它的路径位于 /bin/bash。可是 bash 却告诉我们无此文件,怎么回事?很明显,是 ^M 这个字符影响了 header 一行对于命令解释器的正常识别。那 ^M 这个字符又是什么呢?
不同的操作系统使用不同字符来表示换行。Unix/Linux 使用单个的换行(Line Feed,LF)符作为换行的标记。Windows/DOS 使用 2 个字符:回车(Carriage Return,CR)符和换行符(LF)。MacOS 使用 CR。^M 即为我们在使用 Windows 记事本产生的回车符。更多信息可参见维基百科关于 Newline 的解释。
对于 Linux Deepin 甚至其他发行版来说,一个比较通用的方法是使用 tr 工具来删除多余的回车符,因为它不需要安装额外的工具,且便于理解。
Default
tr -d '\r' < test1 > tmp && mv tmp test1
1
tr-d'\r'<test1>tmp&&mvtmptest1
使用这条命令删除多余的回车符后,该脚本即可正常运行。tr 是 translate 或 transliterate 的缩写。tr 工具从其标准输入(stdin)中转换、缩减或删除字符,并写到标准输出(stdout)。其基本句法为
Default
tr [options] set1 [set2]
1
tr[options]set1[set2]
在这里,tr 从文件 test 中读入,将其中的回车符(\r)删除后输出为文件 tmp,然后又将文件 tmp 重命名为 test1。对于 tr 的更多用法,可查看其 man page 或这篇文章上的说明。