私は組み込みプラットフォームのbashを4.1.9から最新バージョン(4.4.12)に更新しており、エスケープされた引数をスクリプトに渡すこの単純なシナリオで動作の変化を確認しています。
スクリプト/tmp/printarg:
#! /bin/sh
echo "ARG |$*|"
私は次のようにスクリプトを呼び出します。
bash -c "/tmp/printarg \\"abc\\""
私はbash 4.3.42を実行している複数のプラットフォーム(デフォルトx86_64 Linux)とbash 4.1.9と4.2.37を実行している複数の組み込みプラットフォーム(ARMとPPC)でこれを試しましたが、すべて期待した結果が得られました。
38$ bash -c "/tmp/printarg \\"abc\\""
ARG |abc|
ただし、bash 4.4.12(ネイティブX86または組み込みプラットフォーム)を使用してこのコマンドを実行すると、次の結果が表示されます。
$ bash -c "/tmp/printarg \\"abc\\""
ARG |abc\| <<< trailing backslash
コマンドラインで2番目のエスケープされた引用符と閉じる引用符の間にスペースを追加すると、追加のバックスラッシュは表示されなくなります。
$ bash -c "/tmp/printarg \\"abc\\" "
ARG |abc | <<< trailing space, but backslash is gone
まるで故郷に来たような感じです。どんなアイデアがありますか?また、さまざまな互換オプション(compat40、compat41、compat42、compat43)を有効にするように変更してみました。
ベストアンサー1
bash -c "/tmp/printargs \\"abc\\""
あなたが望むものから逃げることはできません。バックスラッシュ - バックスラッシュはエスケープされたバックスラッシュで、呼び出しシェルによって処理されます。したがって、以下を実行するのと同じです。
/tmp/printargs \abc\
二重引用符は次のとおりです。いいえ脱出しました。次のように書くことができます。
bash -c '/tmp/printargs \abc\'
私はあなたが実際に欲しいと思います:
bash -c "/tmp/printargs \"abc\""
bash -cに引用された「abc」を渡して二重引用符をエスケープします。
(あなたが見ている他の動作は、異なるバージョンのbashが入力の最後でエスケープされたすべてを異なる方法で処理することです。)
printargsのPerlバージョン(動作が少し改善されました):
#!/usr/bin/perl
use feature qw(say);
for (my $i = 0; $i < @ARGV; ++$i) {
say "$i: |$ARGV[$i]|";
}