Bashでは、コマンドにコマンドライン引数を指定するとき、どの文字をエスケープする必要がありますか?
彼らはバッシュのメタ文字に制限されています:スペース、タブ、
|
、&
、;
、(
、)
、<
、と>
?
Bashでは、コマンドにコマンドライン引数を指定するとき、どの文字をエスケープする必要がありますか?
彼らはバッシュのメタ文字に制限されています:スペース、タブ、
|
、&
、;
、(
、)
、<
、と>
?
回答:
次の文字は、一部のコンテキストではシェル自体に対して特別な意味を持ち、引数でエスケープする必要がある場合があります。
`
バックティック(U + 0060 Grave Accent)~
チルダ(U + 007E)!
感嘆符(U + 0021)#
ハッシュ(U + 0023番号記号)$
ドル記号(U + 0024)&
アンパサンド(U + 0026)*
アスタリスク(U + 002A)(
左括弧(U + 0028))
右括弧(U + 0029)
(⇥
)タブ(U + 0009){
左中括弧(U + 007B左中括弧)[
左角かっこ(U + 005B)|
縦線(U + 007C縦線)\
バックスラッシュ(U + 005C逆ソリダス);
セミコロン(U + 003B)'
単一引用符/アポストロフィ(U + 0027)"
二重引用符(U + 0022)↩
改行(U + 000A)<
より小さい(U + 003C)>
より大きい(U + 003E)?
疑問符(U + 003F)
スペース(U + 0020)1それらのキャラクターのいくつかは、私がリンクしたものよりも多くのものに、より多くの場所で使用されています。
明示的にオプションであるコーナーケースがいくつかあります。
!
set +H
非対話型シェルのデフォルトであるで無効にできます。{
で無効にできますset +B
。*
そして、?
で無効にすることができますset -f
かset -o noglob
。=
set -k
またはset -o keyword
が有効になっている場合は、等号(U + 003D)もエスケープする必要があります。改行をエスケープするには引用符が必要です。バックスラッシュは役に立たないでしょう。IFSにリストされている他の文字も同様の処理が必要です。あなたがエスケープする必要はありません]
か}
、しかし、あなたはないエスケープする必要があり)
、それはオペレータだから。
これらのキャラクターの中には、本当に逃げる必要がある場合に、他のキャラクターよりも厳しい制限があります。たとえば、a#b
大丈夫a #b
ですが、コメント>
ですが、両方のコンテキストでエスケープする必要があります。とにかくそれらをすべて控えめに逃げても害はなく、細かい区別を覚えるよりも簡単です。
あなたのコマンド名自体はシェルキーワードである場合は(if
、for
、do
)あなたは、あまりにもそれをエスケープするか引用する必要があります。それらの唯一の興味深いものは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を使用している場合、(現時点では)安全です。
!
通常はスクリプトではなく、csh履歴展開が有効になっている場合にのみエスケープする必要があります。[ ! -f a ]
またはfind . ! -name...
大丈夫です。これは、より厳しい制限セクションでカバーされていますが、明示的に言及する価値があるかもしれません。
hash[foo"]"]=
、${var-foo"}"}
、[[ "!" = b ]]
、[[ a = "]]" ]]
、正規表現演算子をするためには[[ x =~ ".+[" ]]
。他のキーワードよりは{
(if
、while
、for
彼らは...そのように認識していないので...)引用符で囲む必要があるだろう
]
)なので、私はそれらをリストしません。引数の位置に引用符を付ける必要のあるキーワードはないと思います。
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文字列には、単一引用符自体を除く任意の文字を含めることができます。
私のコード:
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