263

Bash でエスケープする必要がある文字の包括的なリストはありますか? だけで確認できますsedか?

特に、%エスケープする必要があるかどうかを確認していました。私は試した

echo "h%h" | sed 's/%/i/g'

エスケープせずにうまくいき%ました。%エスケープする必要がないということですか?必要性を確認する良い方法でしたか?

shellそしてより一般的には、エスケープするのと同じ文字bashですか?

4

7 に答える 7

339

shだけでなく、 にも機能する 2 つの簡単で安全なルールがありbashます。

1. 文字列全体を一重引用符で囲みます

これは、一重引用符自体を除くすべての文字で機能します。一重引用符をエスケープするには、その前の引用符を閉じ、一重引用符を挿入してから、引用符を再度開きます。

'I'\''m a s@fe $tring which ends in newline
'

コマンド:sed -e "s/'/'\\\\''/g; 1s/^/'/; \$s/\$/'/"

2. バックスラッシュですべての文字をエスケープします

これは、改行を除くすべての文字で機能します。改行文字には、一重引用符または二重引用符を使用します。空の文字列は引き続き処理する必要があります - に置き換えます""

\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/$/"/'.

2b. 2 の読みやすいバージョン

のような簡単に安全な文字セットがあり、[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 仕様を読むことで簡単に検証できます。bash については、@AustinPhillips がリンクしているリファレンス マニュアルshを確認してください)

于 2013-11-18T16:47:08.823 に答える
77

シェル入力として再利用できる形式

2021 年 2 月の編集: ${var@Q}

bash では、Parameter ExpansionParameter transformation@コマンドを使用して、変数の内容を保存できます。

${parameter@operator}
       Parameter transformation.  The expansion is either a transforma‐
       tion of the value of parameter or  information  about  parameter
       itself,  depending on the value of operator.  Each operator is a
       single letter:

       Q      The expansion is a string that is the value of  parameter
              quoted in a format that can be reused as input.
...
       A      The  expansion  is  a string in the form of an assignment
              statement or declare command  that,  if  evaluated,  will
              recreate parameter with its attributes and value.

サンプル:

$ var=$'Hello\nGood world.\n'
$ echo "$var"
Hello
Good world.

$ echo "${var@Q}"
$'Hello\nGood world.\n'

$ echo "${var@A}"
var=$'Hello\nGood world.\n'

古い答え

この種のリクエスト用に構築された特別な printfフォーマット ディレクティブ ( ) があります。%q

printf [-v 変数] フォーマット [引数]

 %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) ASCII バイトを使用したクイック チェック:

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      

最初のフィールドはバイトの 16 進値、2 番目のフィールドはE文字をエスケープする必要がある場合、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 
于 2015-01-07T10:38:03.963 に答える
47

他の誰かが RTFM を使用する必要がないようにするには... bashで:

文字を二重引用符で囲むと$、引用符内のすべての文字のリテラル値が保持されます。`\!

...したがって、それら (およびもちろん引用自体) をエスケープしても、おそらく問題ありません。

より保守的な「疑わしい場合はエスケープする」アプローチを取る場合は、識別子文字 (つまり、ASCII 文字、数字、または「_」) をエスケープしないことで、代わりに特別な意味を持つ文字を取得することを回避できるはずです。これらが (つまり、いくつかの奇妙な POSIX 風のシェルで) 特別な意味を持ち、したがってエスケープする必要があることはほとんどありません。

于 2014-03-03T23:00:30.853 に答える
18

Bourne または POSIX シェルでは、エスケープが必要な文字が Bash とは異なります。一般に、(非常に) Bash はこれらのシェルのスーパーセットであるため、エスケープするものはすべてshellBash でエスケープする必要があります。

良い一般的なルールは、「疑わしい場合は回避する」ことです。ただし、一部の文字をエスケープすると、 のような特別な意味が得られます\n。これらは、およびのman bash下のページにリストされています。Quotingecho

それ以外は、英数字以外の文字をエスケープする方が安全です。私は単一の決定的なリストを知りません。

マニュアルページには、それらすべてがどこかにリストされていますが、1 か所にリストされているわけではありません。言語を学ぶ、それが確実な方法です。

私を捕まえたのは!. これは、Bash (および csh) の特殊文字 (履歴拡張) ですが、Korn シェルにはありません。問題さえecho "Hello world!"与えます。いつものように一重引用符を使用すると、特別な意味が取り除かれます。

于 2013-04-03T09:53:01.323 に答える
5

オートコンプリートを使用すると、bash が一部の文字を自動的にエスケープすることに気付きました。

たとえば、 という名前のディレクトリがある場合dir:A、bash は次のようにオートコンプリートします。dir\:A

これを使用して、ASCII テーブルの文字を使用していくつかの実験を実行し、次のリストを導き出しました。

オートコンプリートで bash エスケープする文字: (スペースを含む)

 !"$&'()*,:;<=>?@[\]^`{|}

bash がエスケープしない文字:

#%+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_abcdefghijklmnopqrstuvwxyz~

/(ディレクトリ名に使用できないため、除外しました)

于 2016-01-30T02:58:37.043 に答える