# 该文件使用了 dos 格式的换行符 $ od -bc dosnewline.sh 0000000 043 041 057 142 151 156 057 163 150 015 012 015 012 145 143 150 # ! / b i n / s h \r \n \r \n e c h 0000020 157 040 042 124 150 151 163 040 151 163 040 141 040 146 151 154 o " T h i s i s a f i l 0000040 145 040 167 151 164 150 040 144 157 163 040 156 145 167 154 151 e w i t h d o s n e w l i 0000060 156 145 042 015 012 015 012 015 012 n e " \r \n \r \n \r \n 0000071 # 使用 sh 执行的时候就会有一个报错 $ sh dosnewline.sh : command not found 2: This is a file with dos newline : command not found 4: : command not found 5: # 获取脚本的返回码也不是0,在一些自动化调用的场景中就会认为脚本执行失败,从而引发后续的问题 $ echo $? 127 # 退出码 127 的意思是 command not foud,对应具体的 dos 换行符所在的行
正是因为不同操作系统默认的换行符不同,导致在 Windows 下编写的文件采用了 Windows 下的换行符。而不幸的是 sh 做为 Linux 下的应用,只认识 Unix(包括 Linux)下的换行符,引发的文章开头的问题。
解决方法
解决的方法有很多,从脚本来源上说,最好我们在编辑过程中就指定使用的换行符,大多数编码常用编辑器例如 Notepadd++ 等都支持这个选项,如下图在 Notepadd++ 的右下角会显示换行符的类型。千万不要使用 Windows 自带的记事本来编写 shell 脚本,记事本是不支持调整换行符的。
除了在编写阶段注意,脚本编写完成后,还可以通过 $ sh -x hello.sh 的方式来检查脚本是否有语法错误,对于本文提供的示例来说输出结果如下,可以看到输出结果给出提示多了 \r 的字符。
1 2 3 4 5 6 7 8 9
$ sh -x dosnewline.sh + $'\r' : command not found 2: ' echo 'This is a file with dos newline This is a file with dos newline + $'\r' : command not found 4: + $'\r' : command not found 5:
$ tr -d '\r' < dosnewline.sh > dosnewline.sh-tr # 使用 od 比较两个文件,后续的脚本可类似方式比较 $ od -bc dosnewline.sh-tr 0000000 043 041 057 142 151 156 057 163 150 012 012 145 143 150 157 040 # ! / b i n / s h \n \n e c h o 0000020 042 124 150 151 163 040 151 163 040 141 040 146 151 154 145 040 " T h i s i s a f i l e 0000040 167 151 164 150 040 144 157 163 040 156 145 167 154 151 156 145 w i t h d o s n e w l i n e 0000060 042 012 012 012 " \n \n \n 0000064 $ od -bc dosnewline.sh 0000000 043 041 057 142 151 156 057 163 150 015 012 015 012 145 143 150 # ! / b i n / s h \r \n \r \n e c h 0000020 157 040 042 124 150 151 163 040 151 163 040 141 040 146 151 154 o " T h i s i s a f i l 0000040 145 040 167 151 164 150 040 144 157 163 040 156 145 167 154 151 e w i t h d o s n e w l i 0000060 156 145 042 015 012 015 012 015 012 n e " \r \n \r \n \r \n 0000071 $ awk '{ sub("\r$", ""); print }' dosnewline.sh > dosnewline.sh-awk $ sed 's/\r//' dosnewline.sh > dosnewline.sh-sed