4.4の変更をエスケープするbash見積

4.4の変更をエスケープするbash見積

私は組み込みプラットフォームの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]|";
}

答え2

bash -c "/tmp/printargs \\"abc\\""

これはあなたが望むことであると確信していますか?コマンドを効果的に実行すると、set -xコマンドの実行が次のように表示されます。

bash -c '/tmp/printargs \abc\'

つまり、バックスラッシュで終わる文字列をシェルに渡します。最初の引用符付き文字列にはエスケープされたバックスラッシュが含まれ、その後には引用符のないエスケープされたバックスラッシュabcと引用符で囲まれた空の文字列が順番に含まれます。 (Stackexchangeの完成した構文の強調表示がabc引用符の解除をどのように表示するかを参照してください。)

最後に引用符なしでバックスラッシュを入力することは意味がありません。バックスラッシュは、次の文字をエスケープしたり、次のような改行文字で削除される連続行を開始したりできます。

$ bash -c $'echo "foo\\\nbar"'                                                                                                              
foobar 

この場合、どちらもありません。次のいずれかを実行しようとすることができます。

bash -c "/tmp/printargs \"abc\""
bash -c '/tmp/printargs "abc"'

両方とも出力を生成しますARG |abc|


より簡単なテストにより、シェル間の違いを確認できます。

$ bash -c 'echo $BASH_VERSION; echo abc\'
4.4.12(1)-release
abc\

$ ./bash -c 'echo $BASH_VERSION; echo abc\'
4.3.30(1)-release
abc

$ dpkg -l dash |grep ^i
ii  dash           0.5.8-2.4    amd64        POSIX-compliant shell
$ dash -c 'echo abc\'
abc\

$ dpkg -l zsh |grep ^i
ii  zsh            5.3.1-4+b2   amd64        shell with lots of features
$ zsh -c 'echo abc\'
abc

推測する必要がある場合は、次の変更の原因を探し始めます。

この資料では、bash-4.4-alphaのバージョンとbash-4.4-alphaの間の変更について詳しく説明します。
以前のバージョン、bash-4.3-release。

1. Bashの変更点

cccc。読んで評価が中断されるバグを修正しました。
      引用符のないバックスラッシュで終わる文字列で、またはソーシング時にコマンド
      引用符のないバックスラッシュで終わるファイル。

答え3

これを説明します。

$ bash -c "/tmp/quotefail \\"abc\\" "
ARG |abc |            <<< trailing space, but backquote is gone

@ilkkachuが説明したように、set -xこれがどのように説明されるかを見てみましょう。

+ bash -c '/tmp/quotefail \abc\ '

もちろん、「\a」は「a」、「\」は「」なので、/tmp/quotefailから受け取ったパラメータは「abc」で、結果は次のようになります。

ARG |abc |

最初のテストでは、バックスラッシュの後ろに何も出ていないので、まだバックスラッシュです。

関連情報