ファイルを開いて作成するときのBash拡張の非対称

ファイルを開いて作成するときのBash拡張の非対称

Bashの正規表現で、次の非対称の例を見つけましたが、これは私を混乱させます。私がやっていることが非標準的なので、この動作を引き起こしているのか、または私が欠落しているこの動作の背後にあるロジックが何であるかを知りたいのです。

ファイルを開く

file1.txtというファイルを含むディレクトリがあるとしますfile20.txt。お気に入りのテキストエディタでそのファイルを開きたいです。この目的のために、Bashはある意味でディレクトリの内容を「読んで」Vimに渡す必要があります。これを達成するには、次の正規表現を使用できます。

vim file{[1-9],1[0-9],20}.txt

これはうまくいきます。このコマンドを実行するとVimが開き、バッファリストfile1.txtfile20.txt

ファイルの作成

今、私たちが別のシナリオにあると想像してみてください。空のディレクトリから始めfile1.txtfile20.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パターンと一致する既存のファイル。重要な点は、パターンのいずれかに一致するファイルがない場合文字通りパターンをとる

だから開くとどうなりますか?

  1. vim file{[1-9],1[0-9],20}.txtに拡張vim file[1-9].txt file1[0-9].txt file20.txt
  2. vim file[1-9].txt file1[0-9].txt file20.txtvim file1.txt file2.txt ... file20.txtのために拡張されます。このファイルはすべて存在します(そうだろういいえその数値の範囲内に存在しないファイルに展開されます)
  3. vimこのファイルをすべて開きます。

ただし、touchたとえば、同じパラメータを使用する場合存在しないファイルを作成してください。、何が起こるのか

  1. touch file{[1-9],1[0-9],20}.txtに拡張touch file[1-9].txt file1[0-9].txt file20.txt
  2. パターンに一致するファイルがないので[1-9]1[0-9]および20保持されます。文字通り
  3. 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パターンを指定すると、ファイル名が一致しないため、ファイルで動作する多くのプログラムが自動的に読み取りを試みるため、これを使用します。オプションに注意しないと、奇妙な副作用が発生する可能性があります。

また、nullglobBashにはfailglob一致しないglobがある場合は、コマンドを実行する代わりにエラーを表示するオプションがあります。

関連情報