角かっこがシェル拡張を防止するのはなぜですか?

角かっこがシェル拡張を防止するのはなぜですか?

「4800483343」はディレクトリで、「file1」と「file2」はその中にある2つのファイルです。

なぜ次のような状況が発生しますか?

$ ls 4800483343
file1 file2

$ md5sum 4800483343/*
36468e77d55ee160477dc9772a99be4b  4800483343/file1
29b098f7d374d080eb006140fb01bbfe  4800483343/file2

$ mv 4800483343 4800[48]3343

$ md5sum 4800[48]3343/*
md5sum: 4800[48]3343/*: No such file or directory

$ md5sum '4800[48]3343'/*
36468e77d55ee160477dc9772a99be4b  4800[48]3343/file1
29b098f7d374d080eb006140fb01bbfe  4800[48]3343/file2

この問題を引き起こす可能性がある他の文字は何ですか?

答え1

元の質問に答える

角かっこがシェル拡張を防止する理由

角かっこはシェルの拡張を防ぎませんが、引用符は避けます。

実際に実行したコマンドは次のようになりました。

これにより、次のファイルでmd5sumが実行されますdir/

$ md5sum d[i]r/*
02fdd7309cef4d392383569bffabf24c  dir/file1
db69ce7c59b11f752c33d70813ab5df6  dir/file2

これにより、角かっこが拡張されないように引用符がdir移動されます。d[i]r

$ mv dir 'd[i]r'

dirもう存在しないディレクトリを探します。

$ md5sum d[i]r/*
d[i]r/*: No such file or directory

引用符のため、次のエントリは次の名前の新しいディレクトリにありますd[i]r

$ md5sum 'd[i]r'/*
02fdd7309cef4d392383569bffabf24c  d[i]r/file1
db69ce7c59b11f752c33d70813ab5df6  d[i]r/file2

修正された質問に答えてください

修正された質問にはディレクトリ4800483343があり、次のコマンドが実行されます。

mv 4800483343 4800[48]3343

このコマンドを実行したときに発生することは、globが4800[48]3343既存のディレクトリと一致するかどうかによって異なります。一致するディレクトリがない場合は、それ自体が4800[48]3343展開され、4800[48]3343ディレクトリ4800483343がディレクトリに移動します4800[48]3343

ついに:

  1. このコマンドは、md5sum 4800[48]3343/* globと一致するディレクトリがないため、「該当するファイルまたはディレクトリがありません」というエラーを返します4800[48]3343

  2. 引用符はグローバル拡張を防ぐため、このコマンドはmd5sum '4800[48]3343'/*ファイルを正しく検索します。

グローバル例

2つのファイルを作成しましょう。

$ touch a1b a2b

次の球を見てみましょう。

$ echo a[123]b
a1b a2b
$ echo a?b
a1b a2b
$ echo *b
a1b a2b

答え2

角かっこ式は任意の数を表します。一つ可能な一致文字一つキャラクターの位置。この単純な経験則は、マルチバイト文字と[[.組み合わせ要素.]]および/または同等クラスの処理を開始するとぼやけてしまう傾向がありますが、それでもなお、これらの文字に対する複数文字の一致を完全にサポートしていないプログラムがたくさんあります。すべてのロケールに対して、ASCII 数値 0-9 は常に一致し、角括弧式内で順番にソートされます。 POSIXでは、少なくとも最後の数字は真でなければなりません。[[==]]

たとえば、

cd /tmp
for d in 0 1 2 3 4 5 6 7 8 9; do mkdir "$d"; done
ls [0123]

0:

1:  

2:

3:

デフォルトでは、単一の[角かっこ式]シェルglobはより具体的な?char globです。

echo ?/; echo [2468]/

0/ 1/ 2/ 3/ 4/ 5/ 6/ 7/ 8/ 9/
2/ 4/ 6/ 8/

したがって、シェル glob は、次の4800[48]33432 つの現在のディレクトリファイル名のいずれかと一致します。

480043343
480083343

...しかし、そうではありません...

4800483343
4800843343
4800[48]3343

ファイル名にリテラル角かっこを使用するには、角かっこ式で角かっこを一致させることができます。

touch 4800\[48]3343
echo 4800[[]48[]]3343

4800[48]3343

シェルの角かっこワイルドカードにも引用符があまり必要ありません。シェルは、リストのコンテキストで glob 式の始まりとして 3 文字を認識します。

* ? [

左角かっこがない右角括弧は別の文字にすぎず、引用する必要はありません。

echo ]

]

したがって、ペアの開かれた括弧だけを引用すると、常に文字通り解釈されます。それ以外の場合は、いつでもワイルドカードを完全に無効にできます。

set -f

余暇に戻ってください。

set +f

答え3

4800483343ディレクトリ名をに変更すると、メタ文字をエスケープするために引用形式を使用する4800[48]3343必要があります。[ ]これはすべて機能します:

$ ls 4800\[48\]3343/*
$ ls "4800[48]3343"/*
$ ls '4800[48]3343'/*

すべて正しく印刷されます。

4800[48]3343/file1  4800[48]3343/file2

ただし、メタ文字を保持し[]引用符なしでそのままにしておくと、「パス名の拡張」の角括弧の説明として解釈されます。 bashのマニュアルで「パス名拡張」を検索すると、次のようになります。

[...]は含まれている文字の1つと一致します。

これがどのように機能するかを説明するテキストがあります。簡単に言うと:

A [abc] will match ONE character, either an `a`, an `b` or an `c`.

したがって、引用符がない場合またはに4800[48]3343一致します。どちらもディレクトリではなく、ディレクトリがないため拡張されません。より複雑な拡張はディレクトリと一致し、拡張が機能します。480043343480083343
4800[48]3343ls 4800[48]3343/*

$ ls 4800$'\133'[48][48]$'\135'3343/*

しかし、たぶん私はここで話題に深く入っているかもしれません。 :-)

関連情報