バッシュマニュアルから
set -x
コマンド、大文字と小文字、選択、および算術コマンドと、その引数または関連する単語のリストを含む単純なコマンドのトレースを印刷します。拡張後実行前。 PS4変数の値が拡張され、結果の値がコマンドおよび拡張引数の前に印刷されます。
しかし、印刷された痕跡は正確に拡張後の結果ではなく、実行前の結果であることがわかりました。特に、トレースは引用符が削除された後に行われますが、出力には引用符やバックスラッシュが追加されています。これは、元のコマンドを実行したのと同じ結果を得るために、シェルからコマンドで出力を実行できるように見えます。なぜそんなことですか?
それでは、拡張後の実行前の実際の中間解析結果をトレース出力からどのように推論できますか?
たとえば、unset の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
3つの引数foo
、bar
andを取ったのか、qux
2つの引数andfoo bar
を取っqux
たのか(たとえば元のコマンドだったからcp "foo bar" qux
)、2つの引数foo
andを取ったのかbar qux
、実際に名前のついたコマンドなのかcp foo bar qux
などがわかる方法ありません。トレースを明確にするために、bashは引用符を使用します。フォローする引用を選択してください。考えられる方法Bashスクリプトでこのコマンドを実行します。
たとえば、トレースは、コマンドが+ echo '$var'
1echo
つの引数(4文字の文字列)で実行されたことを示します$var
。このコマンドを実行する方法はいくつかあります。たとえば、次のようになります。
echo '$var'
echo \$var
echo \$\v\a\r
echo "\$v"\a''''r
echo "$a" # after running a='$var'
答え2
トレースでは、可能な限り強い引用符を使用しているようです。推測する必要がある場合は、次の例のように、シェル環境変数の変更に関係なく、結果を簡単に再現できます。
$ echo '$var'
+ echo '$var'
$var
二重引用符は、次のように「より単純な」(つまり、エスケープされていない)コピーを許可するようです。
$ echo \\ # why is the trace print out not: echo \\
+ echo '\'
\
ただし、'
sをコピーするときは強い引用符を選択するので、エスケープする必要があります。弱い引用符を使用するか強い引用符を使用するかを心配するよりも、これは簡単だと思います。これはエッジケースの確認を混乱させる可能性があります。