如何防止 bash 标记化字符串变量扩展?

How can prevent bash tokenising string variable expansion?

我不太了解 bash shell 这部分的术语。在一个具体但关键的案例中,我的脚本与此效果冲突:

Objective

在脚本中执行此命令链,其中 awk 表达式 (-e) 来自一个变量。此示例在它是脚本参数时有效。

echo "test string" | awk  -e { print [=11=]; }

问题示例

在命令行上,我正在寻求生成以下输出:“test string”,viz.:

$ optE="-e "
$ argE="{ print $0; }"
$ set -x; echo  "test string" | awk  $optE$argE ; set +x
+ awk -e '{' print '[=12=];' '}'
+ echo 'test string'
awk: cmd. line:1: {
awk: cmd. line:1:  ^ unexpected newline or end of string
+ set +x

在某种程度上我可以看到发生了什么。有没有 good/best 方法可以在 $argE 变量扩展后不对其进行标记化?

如您所知,在命令行中键入相同的命令:

$ echo "test string" | awk   -e '{ print [=13=]; }'
test string

因为表达式用单引号括起来了。我还没有找到使用变量来实现这一点的方法...

$ optE="-e "
$ argE="'{ print $0; }'"
$ set -x; echo  "test string" | awk  $optE$argE ; set +x
+ echo 'test string'
+ awk -e ''\''{' print '[=14=];' '}'\'''
awk: cmd. line:1: '{
awk: cmd. line:1: ^ invalid char ''' in expression
+ set +x

不用说,我在 Whosebug 上是因为我在其他问题中尝试和阅读的东西,等等。没有给出理想的结果。

应用分词扩展 替换 unquoted 变量扩展(${var}$var)之后通过它的扩展。无论引号如何,单词拆分都会在(空白)空格上拆分结果。无论你在字符串中放入什么,如果变量扩展没有被引用,结果将是分词。要影响分词,您必须更改扩展变量的方式,而不是变量的内容(即将 $var 更改为 "$var")。

Is there a good/best way to not have the $argE variable tokenised after it is expanded?

是的,引用扩展。经验法则:从不 $var 总是 "$var"。另外,用 shellcheck 检查你的脚本。

在你的情况下,很简单,只需将要执行的内容赋给变量,并引用扩展即可:

optE="-e"
argE='{ print [=10=]; }'
echo "test string" | awk "$optE" "$argE" 
                         ^^^^^^^ - variable expansion inside quotes

更多情况,使用bash数组arr=(-e '{ print [=17=]; }'),适当awk "${arr[@]}"展开

研究:https://www.gnu.org/software/bash/manual/html_node/Shell-Operation.html , bash manual shell expansions , https://mywiki.wooledge.org/BashFAQ/050 https://mywiki.wooledge.org/Quotes https://mywiki.wooledge.org/BashPitfalls , When should I wrap quotes around a shell variable? https://github.com/koalaman/shellcheck/wiki/Sc2086 .