Bashの正規表現で、次の非対称の例を見つけましたが、これは私を混乱させます。私がやっていることが非標準的なので、この動作を引き起こしているのか、または私が欠落しているこの動作の背後にあるロジックが何であるかを知りたいのです。
ファイルを開く
file1.txt
というファイルを含むディレクトリがあるとしますfile20.txt
。お気に入りのテキストエディタでそのファイルを開きたいです。この目的のために、Bashはある意味でディレクトリの内容を「読んで」Vimに渡す必要があります。これを達成するには、次の正規表現を使用できます。
vim file{[1-9],1[0-9],20}.txt
これはうまくいきます。このコマンドを実行するとVimが開き、バッファリストfile1.txt
にfile20.txt
。
ファイルの作成
今、私たちが別のシナリオにあると想像してみてください。空のディレクトリから始めfile1.txt
てfile20.txt
。残念ながら、この場合、前のコマンドは機能しません。必要な20個のファイルを作成するのではなく、バッファリストに次のファイルがありました。
file[1-9].txt
file[0-9].txt
file20.txt
[]
したがって、角括弧が正規表現の一部として解釈されるのではなく、名前に組み込まれました。
読んで書くと、なぜこのような非対称性が発生するのですか?将来、このようなことをどのように避けることができますか?
答え1
正規表現を使わずに組み合わせを使用しています。支柱の拡張そしてファイル名拡張(別名ワイルドカード)。中かっこ拡張は単に構文を含む文字列を{ ... }
さまざまな文字列に拡張しますが、ワイルドカード部分は実際に次のことを試みるため、これは重要です。既存のファイルをパターンと一致させる。問題は次のとおりです。 (しかし、正規表現も次の目的で使用されます。既存の文字列をパターンに一致、パターンに基づいて文字列を生成しません)。
特に中かっこ拡張はファイル名拡張の前に実行されることに注意してください。
だから
file{[1-9],1[0-9],20}.txt
シェルからスペースで区切られた3つのトークンに拡張
file[1-9].txt file1[0-9].txt file20.txt
その後、実際のファイル名拡張が適用されます。ここで、シェルはどのファイルが何であるかを確認します。このglobパターンと一致する既存のファイル。重要な点は、パターンのいずれかに一致するファイルがない場合文字通りパターンをとる。
だから開くとどうなりますか?
vim file{[1-9],1[0-9],20}.txt
に拡張vim file[1-9].txt file1[0-9].txt file20.txt
vim file[1-9].txt file1[0-9].txt file20.txt
vim file1.txt file2.txt ... file20.txt
のために拡張されます。このファイルはすべて存在します(そうだろういいえその数値の範囲内に存在しないファイルに展開されます)vim
このファイルをすべて開きます。
ただし、touch
たとえば、同じパラメータを使用する場合存在しないファイルを作成してください。、何が起こるのか
touch file{[1-9],1[0-9],20}.txt
に拡張touch file[1-9].txt file1[0-9].txt file20.txt
- パターンに一致するファイルがないので
[1-9]
、1[0-9]
および20
保持されます。文字通り touch
文字通り名前付き3つのファイルを作成します。
これを防ぎ、その範囲内のすべてのファイルを生成するには、コマンドラインを中括弧拡張に制限するだけです。
touch file{1..20}.txt
(pLumoのコメントでも指摘されています)
参考までに(@Quasimodoによって提案されています)bash
および他の多くのシェルでは、グローブの動作を次のように調整できます。住宅オプション、bash
特定の用途に。shopt -s option
このオプションはここで特に興味深いですnullglob
。これは、シェルにパターンリテラルを残さず、空の文字列にファイル名と一致しないワイルドカードパターンを拡張させるためです。これは、ループを使用してパターンに一致するすべてのファイルを繰り返す場合に特に便利ですfor
。
- いいえオプション
nullglob
、フォームループ
一度実行され、for f in *.txt
$f
次に設定されます。言葉*.txt
現在のディレクトリにファイルがない場合、予期し.txt
ない動作(存在しないファイルで動作しようとしているコードなど)が発生する可能性があります。 - そしてこの
nullglob
オプションを使用すると、シェルはループ本体にまったく入りません。
一方(@Barmarが正しく指摘したように)、stdin
ファイルに「None」と評価されるglobパターンを指定すると、ファイル名が一致しないため、ファイルで動作する多くのプログラムが自動的に読み取りを試みるため、これを使用します。オプションに注意しないと、奇妙な副作用が発生する可能性があります。
また、nullglob
Bashにはfailglob
一致しないglobがある場合は、コマンドを実行する代わりにエラーを表示するオプションがあります。