バッシュでエスケープする必要があるキャラクターの包括的なリストはありますか?それだけで確認できますsed
か?
特に、%
エスケープする必要があるかどうかを確認していました。私は試した
echo "h%h" | sed 's/%/i/g'
エスケープせずにうまくいきました%
。%
エスケープする必要がないという意味ですか?これは必要性をチェックする良い方法でしたか?
そしてより一般的です:それらはエスケープするのshell
と同じ文字bash
ですか?
バッシュでエスケープする必要があるキャラクターの包括的なリストはありますか?それだけで確認できますsed
か?
特に、%
エスケープする必要があるかどうかを確認していました。私は試した
echo "h%h" | sed 's/%/i/g'
エスケープせずにうまくいきました%
。%
エスケープする必要がないという意味ですか?これは必要性をチェックする良い方法でしたか?
そしてより一般的です:それらはエスケープするのshell
と同じ文字bash
ですか?
回答:
だけでsh
なくでも機能する2つの簡単で安全なルールがありbash
ます。
これは、単一引用符自体を除くすべての文字で機能します。単一引用符をエスケープするには、その前の引用符を閉じ、単一引用符を挿入して、引用符を再度開きます。
'I'\''m a s@fe $tring which ends in newline
'
sedコマンド: sed -e "s/'/'\\\\''/g; 1s/^/'/; \$s/\$/'/"
これは、改行を除くすべての文字で機能します。改行文字には、一重引用符または二重引用符を使用します。空の文字列は引き続き処理する必要があります-に置き換えます""
\I\'\m\ \a\ \s\@\f\e\ \$\t\r\i\n\g\ \w\h\i\c\h\ \e\n\d\s\ \i\n\ \n\e\w\l\i\n\e"
"
sedコマンド:sed -e 's/./\\&/g; 1{$s/^$/""/}; 1!s/^/"/; $!s/$/"/'
。
のような安全な文字セットがあり、[a-zA-Z0-9,._+:@%/-]
エスケープせずにそのままにして読みやすくすることができます
I\'m\ a\ s@fe\ \$tring\ which\ ends\ in\ newline"
"
sedコマンド:LC_ALL=C sed -e 's/[^a-zA-Z0-9,._+@%/-]/\\&/g; 1{$s/^$/""/}; 1!s/^/"/; $!s/$/"/'
。
sedプログラムでは、入力の最後の行が改行バイトで終了しているかどうかを確認できないことに注意してください(空の場合を除く)。これが、上記の両方のsedコマンドがそうではないと想定している理由です。引用符で囲まれた改行を手動で追加できます。
シェル変数は、POSIXの意味でのテキストに対してのみ定義されることに注意してください。バイナリデータの処理は定義されていません。重要な実装では、バイナリはNULバイトを除いて機能します(変数はC文字列で実装され、C文字列、つまりプログラム引数として使用されるため)が、latin1などの「バイナリ」ロケールに切り替える必要があります。
(のPOSIX仕様を読むことで、ルールを簡単に検証できますsh
。bashについては、@ AustinPhillipsによってリンクされているリファレンスマニュアルを確認してください)
この種のリクエスト用に作成された特別な printf
フォーマットディレクティブ(%q
)があります。
printf [-v var]形式[引数]
%q causes printf to output the corresponding argument in a format that can be reused as shell input.
read foo
Hello world
printf "%q\n" "$foo"
Hello\ world
printf "%q\n" $'Hello world!\n'
$'Hello world!\n'
これは変数でも使用できます。
printf -v var "%q" "$foo
"
echo "$var"
$'Hello world\n'
128から255までのすべてのバイトはエスケープする必要があることに注意してください。
for i in {0..127} ;do
printf -v var \\%o $i
printf -v var $var
printf -v res "%q" "$var"
esc=E
[ "$var" = "$res" ] && esc=-
printf "%02X %s %-7s\n" $i $esc "$res"
done |
column
これは次のようなものをレンダリングする必要があります:
00 E '' 1A E $'\032' 34 - 4 4E - N 68 - h
01 E $'\001' 1B E $'\E' 35 - 5 4F - O 69 - i
02 E $'\002' 1C E $'\034' 36 - 6 50 - P 6A - j
03 E $'\003' 1D E $'\035' 37 - 7 51 - Q 6B - k
04 E $'\004' 1E E $'\036' 38 - 8 52 - R 6C - l
05 E $'\005' 1F E $'\037' 39 - 9 53 - S 6D - m
06 E $'\006' 20 E \ 3A - : 54 - T 6E - n
07 E $'\a' 21 E \! 3B E \; 55 - U 6F - o
08 E $'\b' 22 E \" 3C E \< 56 - V 70 - p
09 E $'\t' 23 E \# 3D - = 57 - W 71 - q
0A E $'\n' 24 E \$ 3E E \> 58 - X 72 - r
0B E $'\v' 25 - % 3F E \? 59 - Y 73 - s
0C E $'\f' 26 E \& 40 - @ 5A - Z 74 - t
0D E $'\r' 27 E \' 41 - A 5B E \[ 75 - u
0E E $'\016' 28 E \( 42 - B 5C E \\ 76 - v
0F E $'\017' 29 E \) 43 - C 5D E \] 77 - w
10 E $'\020' 2A E \* 44 - D 5E E \^ 78 - x
11 E $'\021' 2B - + 45 - E 5F - _ 79 - y
12 E $'\022' 2C E \, 46 - F 60 E \` 7A - z
13 E $'\023' 2D - - 47 - G 61 - a 7B E \{
14 E $'\024' 2E - . 48 - H 62 - b 7C E \|
15 E $'\025' 2F - / 49 - I 63 - c 7D E \}
16 E $'\026' 30 - 0 4A - J 64 - d 7E E \~
17 E $'\027' 31 - 1 4B - K 65 - e 7F E $'\177'
18 E $'\030' 32 - 2 4C - L 66 - f
19 E $'\031' 33 - 3 4D - M 67 - g
最初のフィールドがバイトのヘキサ値であるE
場合、2番目のフィールドは文字をエスケープする必要がある場合に含まれ、3番目のフィールドはエスケープされた文字の表示を示します。
,
?やのように、常にエスケープする必要がない文字がいくつか表示されることがあります。,
}
{
だから常にではなく、いつか:
echo test 1, 2, 3 and 4,5.
test 1, 2, 3 and 4,5.
または
echo test { 1, 2, 3 }
test { 1, 2, 3 }
しかし注意:
echo test{1,2,3}
test1 test2 test3
echo test\ {1,2,3}
test 1 test 2 test 3
echo test\ {\ 1,\ 2,\ 3\ }
test 1 test 2 test 3
echo test\ {\ 1\,\ 2,\ 3\ }
test 1, 2 test 3
subprocess.Popen(['bash', '-c', 'printf "%q\0" "$@"', '_', arbitrary_string], stdin=subprocess.PIPE, stdout=subprocess.PIPE).communicate()
はシェルで引用された適切なバージョンのを提供しarbitrary_string
ます。
%q
は長い間壊れていました-私の心がうまくいくなら、エラーが修正されました(ただし、まだ壊れている可能性があります)は、約10年間壊れていました。したがって、それに依存しないでください。
shlex.quote()
(> = 3.3、-undocumented-for old pipes.quote()
versions)、この作業も行い、ほとんどの文字列のより人間が読めるバージョン(必要に応じて引用符とエスケープを追加)を生成します。シェルを生成する必要はありません。
,
。組み込みのBash printf -- %q ','
はを提供\,
するが/usr/bin/printf -- %q ','
、,
(エスケープされていない)を提供することを知って驚いた。他の文字も同じ:{
、|
、}
、~
。
他人がRTFMをしなくても済むように... bashで:
二重引用符で文字を囲むことを除いて、全ての文字のリテラル値を保持し
$
、`
、\
、および、履歴展開が有効になっている場合、!
。
...したがって、それら(そしてもちろん引用自体)をエスケープする場合は、おそらく大丈夫です。
より慎重な「疑わしいときはエスケープする」アプローチをとる場合、識別子文字(ASCII文字、数字、または '_')をエスケープしないことで、代わりに特別な意味を持つ文字を取得しないようにすることができます。これらが(たとえば、奇妙なPOSIX風のシェルでは)特別な意味を持つことはほとんどないため、エスケープする必要があります。
print '%q'
テクニックを使用して、ループを実行して、どの文字が特殊であるかを見つけることができます。
#!/bin/bash
special=$'`!@#$%^&*()-_+={}|[]\\;\':",.<>?/ '
for ((i=0; i < ${#special}; i++)); do
char="${special:i:1}"
printf -v q_char '%q' "$char"
if [[ "$char" != "$q_char" ]]; then
printf 'Yes - character %s needs to be escaped\n' "$char"
else
printf 'No - character %s does not need to be escaped\n' "$char"
fi
done | sort
それはこの出力を与えます:
No, character % does not need to be escaped
No, character + does not need to be escaped
No, character - does not need to be escaped
No, character . does not need to be escaped
No, character / does not need to be escaped
No, character : does not need to be escaped
No, character = does not need to be escaped
No, character @ does not need to be escaped
No, character _ does not need to be escaped
Yes, character needs to be escaped
Yes, character ! needs to be escaped
Yes, character " needs to be escaped
Yes, character # needs to be escaped
Yes, character $ needs to be escaped
Yes, character & needs to be escaped
Yes, character ' needs to be escaped
Yes, character ( needs to be escaped
Yes, character ) needs to be escaped
Yes, character * needs to be escaped
Yes, character , needs to be escaped
Yes, character ; needs to be escaped
Yes, character < needs to be escaped
Yes, character > needs to be escaped
Yes, character ? needs to be escaped
Yes, character [ needs to be escaped
Yes, character \ needs to be escaped
Yes, character ] needs to be escaped
Yes, character ^ needs to be escaped
Yes, character ` needs to be escaped
Yes, character { needs to be escaped
Yes, character | needs to be escaped
Yes, character } needs to be escaped
結果の一部は、,
少し疑わしいように見えます。これに関する@CharlesDuffyの入力を取得することは興味深いでしょう。
%q
ことがすべての可能なシェルコンテキストで特別な意味を持つことができるすべての文字をエスケープしますので、シェル内あなたは、文字を使用するために滑走しているところを知りません。,
それ自体は彼女のシェルにとって特別な意味はありませんが、@ F.Hauriが彼の返信で指摘したように、{...}
ブレース展開内では特別な意味があります:gnu.org/savannah-checkouts/gnu/bash/manual/…これは!これはまた、一般的にではなく、特定の状況でのみ拡張が必要です。echo Hello World!
うまくecho test!test
機能しますが失敗します。
エスケープが必要な文字は、BourneまたはPOSIXシェルではBashとは異なります。一般に(非常に)Bashはこれらのシェルのスーパーセットであるため、エスケープするものshell
はすべてBashでエスケープする必要があります。
良い一般的なルールは、「疑わしい場合は、それを回避する」ことです。ただし、一部の文字をエスケープすると、などの特別な意味が与えられます\n
。これらは、およびのman bash
下のページにリストされています。Quoting
echo
それ以外は、英数字以外の文字はエスケープしてください。安全です。私は単一の決定的なリストを知りません。
マニュアルページはそれらをどこかにリストアップしますが、一箇所にはリストしません。言語を学びましょう。それが確実な方法です。
私を見つけたのは!
です。これは、Bash(およびcsh)の特殊文字(履歴拡張)ですが、Kornシェルの特殊文字ではありません。echo "Hello world!"
問題さえ与える。通常どおり、単一引用符を使用すると、特別な意味がなくなります。
sed
エスケープする必要があるかどうかを確認するのに十分なものであるかどうかに疑問がある。ご回答有難うございます!
sed
必要はありません。ほとんど何でもチェックできます。 sed
問題ではないbash
です。一重引用符の中に特殊文字はありません(一重引用符を除く)。そこに文字をエスケープすることもできません。sed
REのメタキャラクタは安全であるとシェルのメタキャラクタと非常に多くの重複を持っているので、コマンドは通常、単一引用符内にある必要があります。例外は、シェル変数を埋め込む場合で、慎重に行う必要があります。
echo
。あなたが入れたものを取り出したら、それをエスケープする必要はありません。:)
私はあなたがbash文字列について話していると思います。エスケープの要件が異なる文字列には、さまざまなタイプがあります。例えば。一重引用符の文字列は、二重引用符の付いた文字列とは異なります。
最良のリファレンスは、bashマニュアルの引用セクションです。
エスケープが必要な文字について説明します。一部の文字は、履歴の拡張など、有効になっているオプションによってはエスケープが必要になる場合があります。
オートコンプリートを使用すると、bashが一部の文字を自動的にエスケープすることに気付きました。
たとえば、という名前のディレクトリがある場合dir:A
、bashは次のようにオートコンプリートしますdir\:A
これを使用して、ASCIIテーブルの文字を使用していくつかの実験を実行し、以下のリストを導き出しました。
オートコンプリートでbashエスケープする文字:(スペースを含む)
!"$&'()*,:;<=>?@[\]^`{|}
bashがエスケープしない文字:
#%+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~
(/
ディレクトリ名では使用できないため、除外しました)
printf %q
が必要な場合は、引数として渡された場合に変更される文字と変更されない文字を確認することをお勧めします。理想的には、文字セット全体を調べます。