Bash shell脚本是否对编码和行尾敏感?
我正在Mac上制作一个NW.js应用程序,希望通过双击图标在开发模式下运行该应用程序。第一步,我要让我的shell脚本工作 在Windows上使用VSCode(我想争取时间),我在项目的根目录下创建了一个Bash shell脚本是否对编码和行尾敏感?,bash,shell,sh,Bash,Shell,Sh,我正在Mac上制作一个NW.js应用程序,希望通过双击图标在开发模式下运行该应用程序。第一步,我要让我的shell脚本工作 在Windows上使用VSCode(我想争取时间),我在项目的根目录下创建了一个runnw文件,其中包含以下内容: #!/bin/bash cd "src" npm install cd .. ./tools/nwjs-sdk-v0.17.3-osx-x64/nwjs.app/Contents/MacOS/nwjs "src" & 但我得到的结果是: $ sh
runnw
文件,其中包含以下内容:
#!/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
$sh./run nw
:未找到命令
:没有这样的文件或目录
:未找到命令
:没有这样的文件或目录
用法:npm
其中是:(snip命令列表)
(snip npm帮助)
npm@3.10.3/usr/local/lib/node\u modules/npm
:未找到命令
:没有这样的文件或目录
:未找到命令
我真的不明白:
- 它似乎将空行作为命令。在我的编辑器(VSCode)中,我尝试将
替换为\r\n
(以防\n
产生问题),但没有任何改变\r
- 它似乎找不到文件夹(带或不带
指令),或者可能不知道dirname
命令cd
- 它似乎不理解
的npm
参数install
- 真正让我感到奇怪的是,它仍然在运行应用程序(如果我手动安装了
)npm
两个文件上的差异显示完全没有差异 有什么区别?什么会使第一个脚本不起作用?我怎么知道 更新 在接受答案的建议后,在返回错误的行尾后,我检查了多个内容。事实证明,由于我从Windows计算机复制了
~/.gitconfig
,所以我的autocrlf=true
,因此每次我在Windows下修改bash文件时,它都会将行结尾重新设置为\r\n
因此,除了运行dos2unix(您必须在mac上使用自制软件安装),如果您使用的是Git,请检查您的配置。是。Bash脚本对脚本本身和它处理的数据中的行尾都很敏感。它们应该有Unix风格的行尾,即每一行都以换行字符(十进制10,ASCII中的十六进制0A)结尾 脚本中的DOS/Windows行结尾 对于Windows或DOS样式的行尾,每行都以回车符结尾,后跟换行符。您可以在cat-v yourfile的输出中看到这个不可见的字符:
$ cat -v yourfile
#!/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
在C转义符号中)不被视为空白。Bash将shebang后面的第一行(由单个回车符组成)解释为要运行的命令/程序的名称
- 由于没有名为
的命令,它将打印^M
:找不到命令
- 由于没有名为
(或“src”^M
)的目录,它将打印src^M
:没有这样的文件或目录
- 它将
而不是install^M
作为参数传递给install
,从而导致npm
投诉npm
hello^M
world^M
sed -i 's/\r$//' filename
然后,在编辑器中以及在将其写入屏幕时,它将看起来完全正常,但工具可能会产生奇怪的结果。例如,grep
将无法找到明显存在的行:
$ grep 'hello$' file.txt || grep -x "hello" file.txt
(no match because the line actually ends in ^M)
追加的文本将覆盖该行,因为回车符会将光标移动到该行的开头:
$ sed -e 's/$/!/' file.txt
!ello
!orld
字符串比较似乎会失败,即使写入屏幕时字符串看起来相同:
$ a="hello"; read b < file.txt
$ if [[ "$a" = "$b" ]]
then echo "Variables are equal."
else echo "Sorry, $a is not equal to $b"
fi
Sorry, hello is not equal to hello
-i
或-in-place
选项的sed
实用程序版本,例如GNUsed
,您可以运行以下命令来剥离尾部回车:
hello^M
world^M
sed -i 's/\r$//' filename
对于其他版本的sed
,可以使用输出重定向写入新文件。确保重定向目标使用不同的文件名(以后可以重命名)
tr
翻译过滤器可用于从输入中删除不需要的字符:
tr -d '\r' <filename >filename.unix
由于这一行很长,以octothorpe(#
)开头,Bash将这一行(以及整个文件)视为一条注释
注:2001年,苹果推出了基于BSD衍生操作系统的MacOSX。因此,OSX也使用Unix风格的LF-only行结尾,从那时起,以CR结尾的文本文件变得极为罕见。尽管如此,我认为值得展示Bash如何尝试解释这些文件。是的。Bash脚本对脚本本身和它处理的数据中的行尾都很敏感。它们应该有Unix风格的行尾,即每一行都以换行字符(十进制10,ASCII中的十六进制0A)结尾
脚本中的DOS/Windows行结尾
对于Windows或DOS样式的行尾,每行都以回车符结尾,后跟换行符。您可以在cat-v yourfile的输出中看到这个不可见的字符:
$ cat -v yourfile
#!/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
在C转义符号中)不被视为空白。Bash将shebang后面的第一行(由单个回车符组成)解释为ru的命令/程序的名称
#!/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
$ tr -d '\r' < dosScript.py > nixScript.py
for f in *$'\r'; do
mv "$f" "${f%$'\r'}"
done
Bash script and /bin/bash^M: bad interpreter: No such file or directory
config/* text eol=lf
run.sh text eol=lf
IFS= read -r somevar # This will not trim CR
IFS=$'\r' read -r somevar # This *will* trim CR
read -r field1 field2 ... # This will not trim CR
IFS=$' \t\n\r' read -r field1 field2 ... # This *will* trim CR
cr="$(printf '\r')"
IFS="$cr" read -r somevar # Read trimming *only* CR
IFS="$IFS$cr" read -r field1 field2 ... # Read trimming CR and whitespace, and splitting fields