コマンドライン引数でエスケープするにはどの文字が必要ですか?


14

Bashでは、コマンドにコマンドライン引数を指定するとき、どの文字をエスケープする必要がありますか?

彼らはバッシュのメタ文字に制限されています:スペース、タブ、 |&;()<、と>


*および?でファイル名をグロブすることを忘れないでください。
ジェフシャラー

ありがとう。cmd line argsでエスケープする必要がある文字の種類を網羅的にリストできますか?
ティム

リストは便利ですが、引用について理解する最も重要なことは次のとおりです。単一引用符の間すべて文字通り、単語分割なしで渡されます。 例外なく。(つまり、一重引用符の中に一重引用符を埋め込む方法はありませんが、それは簡単に回避できます。)
ワイルドカード

回答:


22

次の文字は、一部のコンテキストではシェル自体に対して特別な意味を持ち、引数でエスケープする必要がある場合があります。

それらのキャラクターのいくつかは、私がリンクしたものよりも多くのものに、より多くの場所で使用されています。


明示的にオプションであるコーナーケースがいくつかあります。

  • !set +H非対話型シェルのデフォルトであるで無効にできます。
  • {で無効にできますset +B
  • *そして、?で無効にすることができますset -fset -o noglob
  • =set -kまたはset -o keywordが有効になっている場合は、等号(U + 003D)もエスケープする必要があります。

改行をエスケープするには引用が必要です。バックスラッシュは役に立たないでしょう。IFSにリストされている他の文字も同様の処理が必要です。あなたがエスケープする必要はありません]}、しかし、あなたはないエスケープする必要があり)、それはオペレータだから。

これらのキャラクターの中には、本当に逃げる必要がある場合に、他のキャラクターよりも厳しい制限があります。たとえば、a#b大丈夫a #bですが、コメント>ですが、両方のコンテキストでエスケープする必要があります。とにかくそれらをすべて控えめに逃げても害はなく、細かい区別を覚えるよりも簡単です。

あなたのコマンド名自体はシェルキーワードである場合は(iffordo)あなたは、あまりにもそれをエスケープするか引用する必要があります。それらの唯一の興味深いものはin、それが常にキーワードであることは明らかではないためです。あなたはしていないあなたは(愚か!)それらの一つ後のコマンドを命名しました場合にのみ、引数で使用されるキーワードのためのことを行う必要があります。シェル演算子((&など)は、どこにいても常に引用符で囲む必要があります。


1 ステファンは、他のことに注目しているシングルバイトロケールから空白文字はまた、エスケープが必要です。少なくともCまたはUTF-8に基づくロケールの最も一般的で賢明なロケールでは、上記の空白文字のみです。一部のISO-8859-1ロケールでは、Solaris、BSD、OS Xなど、U + 00A0のノーブレークスペースは空白と見なされます(間違っていると思います)。任意の未知のロケールを処理している場合、文字を含むほぼすべてのものを含めることができますので、幸運を祈ります。

おそらく、空白と見なされるシングルバイトは、空白ではないマルチバイト文字内に出現する可能性があり、引用符で囲む以外にそれをエスケープする方法はありません。これは理論的な懸念ではありません。上記のISO-8859-1ロケールA0では、空白と見なされるそのバイトは、UTF-8エンコード "à"()のようなマルチバイト文字内に現れる可能性がありますC3 A0。これらの文字を安全に処理するには、それらを引用する必要があります"à"。この動作は、スクリプトを記述した環境ではなく、スクリプトを実行する環境のロケール構成に依存します。

この振る舞いは複数の方法で壊れていると思いますが、私たちは配られたハンドをプレーしなければなりません。非自己同期マルチバイト文字セットを使用している場合、最も安全なのはすべてを引用することです。UTF-8またはCを使用している場合、(現時点では)安全です。


ロケールの他のブランクにもエスケープする必要があります(バグのため、現在、マルチバイトの1を除く外
ステファンChazelas

!通常はスクリプトではなく、csh履歴展開が有効になっている場合にのみエスケープする必要があります。[ ! -f a ]またはfind . ! -name...大丈夫です。これは、より厳しい制限セクションでカバーされていますが、明示的に言及する価値があるかもしれません。
ステファンシャゼル

:他の文字は次のように引用符で囲む必要がある状況があることに注意してくださいhash[foo"]"]=${var-foo"}"}[[ "!" = b ]][[ a = "]]" ]]、正規表現演算子をするためには[[ x =~ ".+[" ]]。他のキーワードよりは{ifwhilefor彼らは...そのように認識していないので...)引用符で囲む必要があるだろう
ステファンChazelas

それらがコマンドライン引数である限り、解釈は問題のコマンドまで(ちょうど])なので、私はそれらをリストしません。引数の位置に引用符を付ける必要のあるキーワードはないと思います。
マイケルホーマー

2
組み込み語、ダッシュ、または%を引用しても何もしません。
マイケルホーマー

3

GNU Parallelでは、これは広くテストされ使用されています。

$a =~ s/[\002-\011\013-\032\\\#\?\`\(\)\{\}\[\]\^\*\<\=\>\~\|\; \"\!\$\&\'\202-\377]/\\$&/go;
# quote newline as '\n'                                                                                                         
$a =~ s/[\n]/'\n'/go;

それはでテストされbashdashashkshzsh、とfish。一部の文字は、シェルの一部(バージョン)で引用符で囲む必要はありませんが、上記のテストはすべてのテスト済みシェルで機能します。

単に引用符で囲まれた文字列が必要な場合は、次のようにパイプすることができますparallel --shellquote

printf "&*\t*!" | parallel --shellquote

どのように...私は前に並列で聞いていない
トム・H

@TomH 5分間かけて、私たちがどのようにあなたに連絡できたか考えていただければ幸いです。
オレ丹下

進行の問題だと思います。ほとんどの人は、いくつかの複雑な段階を経るまで、パラレルを必要としないか理解しません。その時までに、xargs、nohupなどがあります。また、私は、スタック交換で問題を解決するために、並列を使用して多くの人々が表示されていないか、私はbashの問題への解決策をグーグルとき
トム・H

1

Perlの軽量エスケープソリューションでは、単一引用符の原則に従います。単一引用符で囲まれたBash文字列には、単一引用符自体を除く任意の文字を含めることができます。

私のコード:

my $bash_reserved_characters_re = qr([ !"#$&'()*;<>?\[\\`{|~\t\n]);

while(<>) {
    if (/$bash_reserved_characters_re/) {
        my $quoted = s/'/'"'"'/gr;
        print "'$quoted'";
    } else {
        print $_;
    }
}

実行例1:

$ echo -n "abc" | perl escape_bash_special_chars.pl
abc

実行例2:

echo "abc" | perl escape_bash_special_chars.pl
'abc
'

実行例3:

echo -n 'ab^c' | perl escape_bash_special_chars.pl
ab^c

実行例4:

echo -n 'ab~c' | perl escape_bash_special_chars.pl
'ab~c'

実行例5:

echo -n "ab'c" | perl escape_bash_special_chars.pl
'ab'"'"'c'

echo 'ab'"'"'c'
ab'c

はい、それは有効なポイントです。私の意見では、ほとんどの人はこのページに着くでしょう。なぜなら、彼らには解決すべき問題があるからです。これは興味深い学術的な議論をするからではありません。だからこそ、少しトピックから外れていても、ソリューションを提供し、そのメリットについて話し合いたいと思います。
ヤリトゥルキア

私のコードは、マイケル・ホーマーの答えの単なる実装です。私は彼がしたこと以上の情報を持ち込むつもりはなかった。
ヤリトゥルキア
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.