繁体   English   中英

变量处理的bash引号在扩展为命令时处理不同

[英]bash quotes in variable treated different when expanded to command

通过例子解释问题......

证明 - 变量扩展后,--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.

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

我担心有一天,参数中的文件名包含一些破坏一切的字符,因此可能过多引用。 我不明白为什么直接在脚本中输入或通过变量提供时相同的命令执行方式不同。 请赐教。

谢谢阅读。

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

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

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

cmd $args

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

唯一的方法是将$IFS设置$IFS包含一些非空白字符; 然后,该字符可以在$args作为单字符分隔符使用。 但是, 没有办法在值中引用字符 ,因此一旦这样做,您选择的字符除了作为分隔符之外不能使用。 这通常不太令人满意。

但是有一个解决方案: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汇编命令的详细说明,从“EXPANSION”部分开始。 值得阅读以获得完整的解释。


笔记:

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM