shell脚本对编码和行尾是否敏感?
我在Mac上制作了一个NW.js应用程序,并希望通过双击图标在开发模式下运行应用程序。 第一步,我试图让我的shell脚本工作。
在Windows上使用VSCode(我想获得时间),我在我的项目的根目录下创建了一个run-nw
文件,其中包含以下内容:
#!/bin/bash
cd "src"
npm install
cd ..
./tools/nwjs-sdk-v0.17.3-osx-x64/nwjs.app/Contents/MacOS/nwjs "src" &
但我得到这个输出:
$ sh ./run-nw
: command not found
: No such file or directory
: command not found
: No such file or directory
Usage: npm <command>
where <command> is one of: (snip commands list)
(snip npm help)
npm@3.10.3 /usr/local/lib/node_modules/npm
: command not found
: No such file or directory
: command not found
我真的不明白:
n
替换rn
n
(如果r
创建问题),但它不会改变任何内容。 dirname
指令),或者它不知道关于cd
命令? npm
的install
参数 npm install
)... 无法正常工作,并怀疑文件本身有些奇怪,我在Mac上直接创建了一个新文件,这次使用vim。 我输入了完全相同的说明,现在它没有任何问题。
两个文件的差异显示了精确的零差异。
有什么区别? 什么可以使第一个脚本不起作用? 我如何知道?
更新
遵循接受的答案的建议,在错误的结尾回来之后,我检查了多件事情。 事实证明,由于我从我的Windows机器上复制了~/.gitconfig
,因此我有autocrlf=true
,所以每次我在Windows下修改bash文件时,都会将行尾重新设置为rn
。
因此,除了运行dos2unix(您将不得不在Mac上使用Homebrew进行安装),如果您使用的是Git,请检查您的配置。
是。 Bash脚本对行尾是敏感的。 它们应该具有Unix风格的行结束符,即每行都以换行符(十进制10,十六进制0A,ASCII)结束。
DOS / Windows行结束
使用Windows或DOS样式的行结束符时,每行都以一个回车符和一个换行符结束。 如果一个脚本文件是用Windows行结束符保存的,Bash将该文件视为
#!/bin/bash^M
^M
cd "src"^M
npm install^M
^M
cd ..^M
./tools/nwjs-sdk-v0.17.3-osx-x64/nwjs.app/Contents/MacOS/nwjs "src" &^M
在这种情况下,回车( ^M
或r
)不被视为空白。 Bash将shebang之后的第一行(由单个回车符组成)解释为要运行的命令/程序的名称。
^M
命令,因此它会输出: command not found
"src"^M
(或src^M
)的目录,因此它会打印: No such file or directory
install^M
而不是install
作为npm
的参数,导致npm
抱怨。 注意:我用插入符号表示非打印字符,即^M
用于表示回车符(在其他上下文中表示为r
); 这与cat -v
和Vim使用的技术相同。
解
解决方案是将文件转换为Unix行尾。
这可以使用dos2unix
程序完成:
dos2unix run-nw
或者在Vim中打开文件并在保存之前运行以下命令:
:set fileformat=unix
注意:使用Cygwin的Bash端口,有一个自定义的igncr
选项可以设置为忽略行尾的回车igncr
(可能是因为某些用户使用本地Windows程序来编辑其文本文件)。
有用的工具
file
实用程序对于快速查看文本文件中使用哪些行结束符非常有用。 以下是针对每种文件类型打印的内容:
Bourne-Again shell script, ASCII text executable
Bourne-Again shell script, ASCII text executable, with CR line terminators
Bourne-Again shell script, ASCII text executable, with CRLF line terminators
: Bourne-Again shell script, ASCII text executable, with CRLF line terminators
dos2unix
实用程序对于在Unix,Mac和DOS行尾之间转换文本文件非常有用。
有用的链接
维基百科有一篇很好的文章,涵盖了标记文本行尾的许多不同方式,这种编码的历史以及不同操作系统,编程语言和互联网协议(如FTP)如何处理新行。
经典的Mac OS系列结局
使用经典Mac OS(pre-OS X)时,每行都以回车符结束(十进制13,十六进制0D,ASCII)。 如果一个脚本文件是用这样的行结尾保存的,Bash只会看到如下这样的一行:
#!/bin/bash^M^Mcd "src"^Mnpm install^M^Mcd ..^M./tools/nwjs-sdk-v0.17.3-osx-x64/nwjs.app/Contents/MacOS/nwjs "src" &^M
由于这条单线以一个八号( #
)开头,所以Bash将这条线(以及整个文件)视为一个单独的评论。
注意:2001年,Apple推出了基于BSD派生的NeXTSTEP操作系统的Mac OS X. 因此,OS X还使用Unix风格的仅限LF的行结束符,此后,以CR终止的文本文件变得非常罕见。 尽管如此,我认为值得展示Bash如何试图解释这些文件。
另一种摆脱不需要的CR(' r')字符的方法是运行tr
命令,例如:
$ tr -d 'r' < dosScript.py > nixScript.py
链接地址: http://www.djcxy.com/p/57191.html
上一篇: Are shell scripts sensitive to encoding and line endings?