Bashでコマンドにコマンドライン引数を指定する場合、エスケープする必要がある文字は何ですか?
それらはBashのメタキャラクターに限定されていますか:スペース、タブ、|
、&
、;
、(
、)
、<
、>
?
次の文字は、一部のコンテキストではシェル自体に特別な意味があり、引数でエスケープする必要がある場合があります。
`
バックティック (U + 0060重大アクセント)~
チルダ (U + 007E)!
感嘆符 (U + 0021)#
ハッシュ (U + 0023番号記号)$
ドル記号 (U + 0024)&
アンパサンド (U + 0026)*
アスタリスク (U + 002A)(
左括弧 (U + 0028))
右括弧 (U + 0029)⇥
) Tab (U + 0009){
左中括弧 (U + 007B左中括弧)[
左角括弧 (U + 005B)|
縦棒 (U + 007C縦線)\
バックスラッシュ (U + 005C逆ソリッド);
セミコロン (U + 003B)'
一重引用符/アポストロフィ (U + 0027)"
二重引用符 (U + 0022)↩
改行 (U + 000A)<
より小さい (U + 003C)>
より大きい (U + 003E)?
疑問符 (U + 003F)それらのキャラクターのいくつかは、私がリンクしたものよりも多くのことで、より多くの場所で使用されています。
明示的にオプションであるいくつかのコーナーケースがあります。
!
は set +H
、これは非対話型シェルのデフォルトです。{
は set +B
。*
および?
は set -f
またはset -o noglob
。=
等号(U + 003D)も set -k
またはset -o keyword
が有効です。改行のエスケープ 引用符が必要 —バックスラッシュは機能しません。 [〜#〜] ifs [〜#〜] にリストされているその他の文字も同様の処理が必要です。エスケープする必要はありません]
または}
、しかしあなたdoはエスケープする必要があります)
演算子だからです。
これらのキャラクターの一部は、他のキャラクターよりも本当にエスケープする必要がある場合により厳しい制限があります。例えば、 a#b
は問題ありませんが、a #b
はコメントですが、>
は両方のコンテキストでエスケープする必要があります。とにかく保守的にすべてをエスケープすることは害にならず、細かい違いを覚えるよりも簡単です。
コマンド名自体がシェルキーワード(if
、for
、do
)の場合は、エスケープまたは引用符で囲む必要があります。それらの中で唯一興味深いのはin
です。これが常にキーワードであるかどうかは明らかではないためです。引数で使用するキーワードについてはしないでください。コマンドの名前を(ばかげて!)シェル演算子((
、&
など)どこにいても常に引用する必要があります。
1Stéphaneは他の single-byteblank character from your locale もエスケープする必要があることに注意しています。最も一般的で実用的なロケールでは、少なくともCまたはUTF-8に基づくロケールでは、上記の空白文字のみです。一部のISO-8859-1ロケールでは、U + 00A0ノーブレークスペースは、Solaris、BSD、およびOS X(誤っていると思います)を含め、空白と見なされます。不明な任意のロケールを扱っている場合は、文字を含め、ほとんど何でも含めることができます。幸運を祈ります。
おそらく、空白と見なされる1バイトが内に空白ではないマルチバイト文字として表示される可能性があり、他の文字をエスケープする方法はありません。全体を引用符で囲むよりも。これは理論的な問題ではありません。上からのISO-8859-1ロケールでは、A0
空白と見なされるバイトは、UTF-8エンコードされた「à」のようなマルチバイト文字内に現れる可能性があります(C3 A0
)。これらの文字を安全に処理するには、それらを引用符で囲む必要があります"à"
。この動作は、スクリプトを作成した環境ではなく、スクリプトを実行している環境のロケール構成に依存します。
この振る舞いは複数の方法で壊れていると思いますが、私たちは対処されたハンドをプレイしなければなりません。非自己同期マルチバイト文字セットを使用している場合、最も安全な方法はすべてを引用することです。 UTF-8またはCを使用している場合は、安全です(現時点では)。
GNU Parallelでは、これはテストされ、広範囲に使用されます:
$a =~ s/[\002-\011\013-\032\\\#\?\`\(\)\{\}\[\]\^\*\<\=\>\~\|\; \"\!\$\&\'\202-\377]/\\$&/go;
# quote newline as '\n'
$a =~ s/[\n]/'\n'/go;
bash
、dash
、ash
、ksh
、zsh
、fish
でテストされています。一部の文字は一部の(バージョン)シェルで引用符を必要としませんが、上記はすべてのテスト済みシェルで機能します。
単に文字列を引用したい場合は、parallel --shellquote
にパイプできます。
printf "&*\t*!" | parallel --shellquote
Perlの軽量エスケープソリューションでは、単一引用符の原則に従っています。単一引用符で囲まれたBash-stringには、単一引用符自体を除く任意の文字を含めることができます。
私のコード:
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