我有一个名为 script.sh 的脚本:
FILE=$1
sed -i.bak "s|needle|pin|g" $FILE
Run Code Online (Sandbox Code Playgroud)
如果我像这样运行它:
bash ./script.sh /var/www/path/to/file
Run Code Online (Sandbox Code Playgroud)
我得到这个回应:
: No such file or directoryth/to/file
Run Code Online (Sandbox Code Playgroud)
如果我自己运行sed,则通过相同的路径:
sed -i.bak "s|needle|pin|g" "/var/www/path/to/file"
Run Code Online (Sandbox Code Playgroud)
它工作正常(甚至正确替换值)。
我究竟做错了什么?
额外的观察:我假设它告诉我入口路径是错误的,但很难说,因为它说“:没有这样的文件或目录/到/文件”,这向我表明其他东西是错误的。也许与回车有关?
file="$1"
sed -i.bak "s|needle|pin|g" "$file"
Run Code Online (Sandbox Code Playgroud)
(您也不应该对非环境变量使用全大写的变量名。)
在 中bash,每个命令行(在它被分成标记之后)经历一系列的shell 扩展,以特定的顺序(强调我的):
- 大括号扩展;
- 波浪号扩展、参数和变量扩展、算术扩展、进程替换和命令替换(以从左到右的方式完成);
- 分词;和
- 文件名扩展。
所以,当你写:
file='filename with spaces'
sed "pat" $file
Run Code Online (Sandbox Code Playgroud)
该$file令牌将进行变量扩展,其次是分词,命令会是这个样子:
sed pat filename with spaces
Run Code Online (Sandbox Code Playgroud)
意思是,sed收到三个词作为文件名,而不是一个。
如果使用双引号,则双引号内发生的参数扩展、命令替换和算术扩展的结果不受分词和文件名扩展的影响。在我们的例子中:
file='filename with spaces'
sed "pat" "$file"
Run Code Online (Sandbox Code Playgroud)
扩展为:
sed "pat" "filename with spaces"
Run Code Online (Sandbox Code Playgroud)
保留文件名中的空格。