来自 bash 手册
set -x
打印简单命令的痕迹,包括命令、case 命令、选择命令以及算术命令及其参数或关联的单词列表在它们展开之后和执行之前。 PS4 变量的值被扩展,并且结果值在命令及其扩展参数之前打印。
但我发现它打印出来的痕迹并不完全是展开后的结果,而是执行前的结果。特别是,跟踪应该在引号删除之后,但打印输出添加了额外的引号或反斜杠,就好像我们可以将打印输出作为 shell 中的命令运行以获得与运行原始命令相同的结果。这是为什么?
那么,如何从跟踪打印输出中推断出扩展之后但执行之前的实际中间解释结果呢?
例如,对于未设置的var
,
$ echo '$var'
+ echo '$var'
$var
$ echo "$var"
+ echo ''
$ echo \$var
+ echo '$var'
$var
$ echo \'$var\' # why is the trace print out not: echo \'\'
+ echo ''\'''\'''
''
$ echo \'
+ echo \'
'
$ echo "'" # why is the trace print out not: echo "'"
+ echo \'
'
$ echo "''" # why is the trace print out not: echo "''"
+ echo ''\'''\'''
''
$ echo \'\' # why is the trace print out not: echo \'\'
+ echo ''\'''\'''
''
$ echo \\ # why is the trace print out not: echo \\
+ echo '\'
\
答案1
引用手册:
在它们展开之后和执行之前
您声称:
但我发现它打印出来的痕迹并不完全是展开后的结果而是执行前的结果
但他们确实如此。展开的结果是单词列表。 Bash 使用引号以明确的方式表示单词列表。 bash 打印的内容不是未删除引号的扩展的中间结果。它是印刷表示字符串列表。
例如,如果跟踪是
+ cp foo bar qux
那么就无法知道该命令是否cp
带有三个参数foo
, bar
and qux
,或者带有两个参数foo bar
and qux
(例如,因为原始命令是cp "foo bar" qux
),或者带有两个参数foo
and bar qux
,或者它是否实际上是一个名为 的命令cp foo bar qux
,等等。为了使跟踪明确,bash 使用引号。选择引用以便跟踪一种可能的方式在 bash 脚本中运行此命令。
例如,trace+ echo '$var'
表示该命令echo
是使用一个参数(4 个字符的字符串 )执行的$var
。运行该命令的方法有很多种,例如:
echo '$var'
echo \$var
echo \$\v\a\r
echo "\$v"\a''''r
echo "$a" # after running a='$var'
答案2
似乎跟踪在可能的情况下选择使用强引号。如果我不得不猜测,这将是为了轻松重现结果,独立于 shell 环境变量的更改,如下例所示:
$ echo '$var'
+ echo '$var'
$var
强引号似乎还允许“更简单”(即非转义)复制,如下所示:
$ echo \\ # why is the trace print out not: echo \\
+ echo '\'
\
然而,在复制'
s 时,由于它选择强引号,因此需要转义它们。我认为这比考虑是否使用弱引号或强引号更简单,这可能会导致边缘情况检查的混乱。