我看过有关此问题的类似文章,但是无法弄清楚如何使执行的代码具有正确的格式,该格式必须为foo --bar "a='b'"
。我对此的最佳尝试是
#!/bin/bash -x
bar='--bar ''"''a='"'"'b'"'"'"'
cmd=(foo $bar)
echo ${cmd[@]}
eval ${cmd[@]}
此输出对于echo
是正确的,但对于eval
是错误的
+ bar='--bar "a='\''b'\''"'
+ cmd=(foo $bar)
+ echo foo --bar '"a='\''b'\''"'
foo --bar "a='b'"
+ eval foo --bar '"a='\''b'\''"'
++ foo --bar 'a='\''b'\'''
使用该选项执行命令的正确方法是什么?
答案 0 :(得分:4)
根据BashFAQ #50的最佳做法代码示例:
#!/usr/bin/env bash
bar=( --bar a="b" )
cmd=(foo "${bar[@]}" )
printf '%q ' "${cmd[@]}" && echo # print code equivalent to the command we're about to run
"${cmd[@]}" # actually run this code
奖金:您的调试输出无法证明您的想法。
"a='b'"
和'a='\''b'\'''
是引用完全相同的字符串的两种不同方式。
要证明这一点:
printf '%s\n' "a='b'" | md5sum -
printf '%s\n' 'a='\''b'\''' | md5sum -
...作为输出发出:
7f183df5823cf51ec42a3d4d913595d7 -
7f183df5823cf51ec42a3d4d913595d7 -
...因此,在代码中解析echo $foo
和eval $foo
的参数之间没有什么不同。
为什么这是真的?因为语法引号不是实际运行的命令的一部分;在外壳程序使用它们确定如何逐个字符解释命令行后,它们将被外壳程序删除。
因此,让我们分解一下set -x
向您显示的内容:
'a='\''b'\'''
...由以下串联在一起的文字字符串组成:
a=
(在单引号上下文中,以单引号引起来并以该引号结尾)'
(在无引号的上下文中,由其前面的反斜杠转义)b
(在单引号上下文中,以单引号引起来并以该引号结尾)'
(在未引用的上下文中) ...其他所有内容都是 syntactic ,对shell有意义,但从未传递给程序foo
。
答案 1 :(得分:0)
如果要进行与echo ${cmd[@]}
中相同的扩展,只需运行以下命令即可:
${cmd[@]}
它将执行:
+ foo --bar '"a='\''b'\''"'
请注意,由于*
未加引号,因此将根据filename expansion进行扩展。