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

我真的不明白:

  • 它似乎将空行作为命令。 在我的编辑器(VSCode)中,我尝试用n替换rn n (如果r创建问题),但它不会改变任何内容。
  • 它似乎没有找到文件夹(有或没有dirname指令),或者它不知道关于cd命令?
  • 它似乎并不理解npminstall参数
  • 那些让我感到奇怪的部分是,它仍然运行应用程序(如果我手动进行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
    

    在这种情况下,回车( ^Mr )不被视为空白。 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实用程序对于快速查看文本文件中使用哪些行结束符非常有用。 以下是针对每种文件类型打印的内容:

  • Unix行结尾: Bourne-Again shell script, ASCII text executable
  • Mac行结尾: Bourne-Again shell script, ASCII text executable, with CR line terminators
  • DOS行结束Bourne-Again shell script, ASCII text executable, with CRLF line terminatorsBourne-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?

    下一篇: Wix: Is there any wix command to create database user?