是时候解决这个困扰我多年的难题了......
我时常遇到这种情况,并认为这是要走的路:
$(comm "$(arg)")
并认为我的观点得到了经验的有力支持。但我不再那么确定了。外壳检查也拿不定主意。两者都是:
"$(dirname $0)"/stop.bash
^-- SC2086: Double quote to prevent globbing and word splitting.
和:
$(dirname "$0")/stop.bash
^-- SC2046: Quote this to prevent word splitting.
背后的逻辑是什么?
(顺便说一句,这是 Shellcheck 版本 0.4.4。)
答案1
你需要使用"$(somecmd "$file")"
.
如果没有引号,带有空格的路径将在 的参数中被分割somecmd
,并且它将定位到错误的文件。所以你需要在里面加引号。
输出中的任何空格somecmd
也会导致拆分,因此您需要在整个命令替换的外部加上引号。
命令替换内的引号对其外部的引号没有影响。Bash 自己的参考手册对此并不太清楚,但是BashGuide 明确提到了它。这POSIX 中的文本也需要它,因为“任何有效的 shell 脚本”允许进入$(...)
:
对于该
$(command)
形式,左括号后面到匹配右括号的所有字符构成命令。任何有效的 shell 脚本都可用于命令,但仅包含产生未指定结果的重定向的脚本除外。
例子:
$ file="./space here/foo"
A。没有引号,dirname
同时处理./space
和here/foo
:
$ printf "<%s>\n" $(dirname $file)
<.>
<here>
b.里面的引号,dirname
processes ./space here/foo
,giving ./space here
,被分成两部分:
$ printf "<%s>\n" $(dirname "$file")
<./space>
<here>
C。外部引号,dirname
处理./space
和here/foo
,在不同的行上输出,但是现在这两行形成一个参数:
$ printf "<%s>\n" "$(dirname $file)"
<.
here>
d.引用内部和外部,这给出了正确答案:
$ printf "<%s>\n" "$(dirname "$file")"
<./space here>
(如果只处理第一个参数,可能会更简单dirname
,但这不会显示情况 a 和 c 之间的差异。)
请注意,对于dirname
(可能还有其他),您还需要添加--
, 以防止文件名被视为选项,以防它恰好以破折号开头,因此请使用"$(dirname -- "$file")"
.