4

通过例子解释问题...

表明当变量展开时, --chapters 之后的单引号被转义(我没想到会这样):

prompt@ubuntu:/my/scripts$ cat test1.sh
#!/bin/bash
actions="--tags all:"
actions+=" --chapters ''"
mkvpropedit "$1" $actions

prompt@ubuntu:/my/scripts$ ./test1.sh some.mkv
Error: Could not open '''' for reading.

现在由于某种原因 mkvpropedit 接收双引号作为文件名的一部分(我也没想到会这样):

prompt@ubuntu:/my/scripts$ cat test1x.sh
#!/bin/bash
command="mkvpropedit \"$1\""
command+=" --tags all:"
command+=" --chapters ''"
echo "$command"
$command

prompt@ubuntu:/my/scripts$ ./test1x.sh some.mkv
mkvpropedit "some.mkv" --tags all: --chapters ''
Error: Could not open '''' for reading.

上面的 echo'd 命令似乎是正确的。将相同的文本放在另一个脚本中会产生预期的结果:

prompt@ubuntu:/my/scripts$ cat test2.sh
#!/bin/bash
mkvpropedit "$1" --tags all: --chapters ''

prompt@ubuntu:/my/scripts$ ./test2.sh some.mkv
The file is being analyzed.
The changes are written to the file.
Done.

任何人都可以解释为什么报价没有按预期运行。我发现搜索这个问题很困难,因为网络上有很多其他的引用讨论。如果没有例子,我什至不知道如何解释这个问题。

恐怕有一天参数中的文件名包含一些会破坏所有内容的字符,因此可能会过度引用。我不明白为什么直接在脚本中键入或通过变量提供相同的命令时执行不同。请赐教。

谢谢阅读。

4

1 回答 1

5

要记住的重要一点是,引号仅在最初解析命令行时被删除一次。$foo作为参数替换 ( ) 或命令替换 ( )的结果插入命令行的引号$(cmd args)不被视为特殊字符。[注1]

这似乎与空格和 glob 元字符不同。分词和路径名扩展发生在参数/命令替换之后(除非替换发生在引号内)。[笔记2]

结果是几乎不可能创建一个 bash 变量$args,使得

cmd $args

如果$args包含引号,则不会删除它们。里面的单词$args由空格序列分隔,而不是单个空格字符。

唯一的方法是设置$IFS包含一些非空白字符;然后该字符可以在内部$args用作单字符分隔符。但是,无法在 value 中引用字符,因此一旦这样做,您选择的字符就不能用作分隔符。这通常不是很令人满意。

不过有一个解决方案:bash 数组。

如果你把$args它变成一个数组变量,那么你可以用重复引号语法来扩展它:

cmd "${args[@]}"

它为 的每个元素生成一个单词$args,并抑制这些单词的单词拆分和路径名扩展,因此它们最终成为文字。

因此,例如:

actions=(--tags all:)
actions+=(--chapters '')
mkvpropedit "$1" "${actions[@]}"

可能会做你想做的事。也会:

args=("$1")
args+=(--tags)
args+=(all:)
args+=(--chapters)
args+=('')
mkvpropedit "${args[@]}"

所以会

command=(mkvpropedit "$1" --tags all: --chapters '')
"${command[@]}"

我希望这是半清楚的。

man bash(或在线版本)包含 bash 如何组装命令的详细说明,从“扩展”部分开始。值得一读以获得完整的解释。


笔记:

  1. 这不适用于在eval命令bash -c行处理后再次评估其参数的命令。但那是因为命令行处理发生了两次。

  2. 分词与“将命令分成单词”不同,后者在解析命令时发生。一方面,分词使用 的值作为分隔符$IFS,而命令行解析使用空格。但是这些都不是在引号内完成的,所以它们在这方面是相似的。在任何情况下,在参数替换之前和之后,单词都会以一种或另一种方式拆分。

于 2013-11-18T00:06:53.063 回答