ほとんどのシェルではnullglob デフォルトではありません。つまり、たとえば、このコマンドを実行した場合
ls *
空のディレクトリでは、 *が展開されます リテラル*へのグロブ 、代わりに引数の空のリストに。 * となるように、その動作を変更する方法があります。 空のディレクトリにあると、引数の空のリストが返されます。これは、より直感的に見えるでしょう。
それで、 nullglobが理由があります デフォルトでは無効になっていますか?もしそうなら、その理由は何ですか?
承認された回答:
nullglob オプション(ところで、これは zsh 発明、数年後に bashに追加されました ( 2.0 ))多くの場合、理想的ではありません。そしてls 良い例です:
ls *.txt
または、より正確な同等物:
ls -- *.txt
nullglobを使用 onはlsを実行します ls-。として扱われる引数なし (現在のディレクトリをリストします)一致するファイルがない場合、これはおそらく lsを呼び出すよりも悪いです リテラルの*。txtを使用 引数として。
ほとんどのテキストユーティリティでも同様の問題が発生します:
grep foo *.txt
fooを探します txtがない場合はstdinに ファイル。
より賢明なデフォルトであり、csh、tcsh、zsh、またはfish 2.3以降(および初期のUnixシェル)の1つは、globが一致しない場合にコマンドを完全にキャンセルすることです。
bash (バージョン3以降)には failglobがあります そのためのオプション( ash とは対照的に、この議論に興味があります 、AT&T ksh またはzsh 、 bash オプションのローカルスコープをサポートしていません(ただし、4.4で変更されます)。グローバルに有効にすると、そのオプションはbash-completion関数などのいくつかの機能を壊します。
cshとtcshはzshとは少し異なることに注意してください 、 fish またはbash-O failglob 次のような場合:
ls -- *.txt *.html
コマンドをキャンセルするために、すべてのグロブを一致させないようにする必要がある場合。たとえば、txtファイルが1つあり、htmlファイルがない場合、次のようになります。
ls -- file.txt
zshでその動作を得ることができます setopt cshnullglobを使用 zshでそれを行うためのより賢明な方法ですが 次のようなグロブを使用することになります:
ls -- *.(txt|html)
zshで およびksh93 、 nullglobを適用することもできます グロブごとに、これはグローバル設定を変更するよりもはるかに賢明なアプローチです:
files=(*.txt(N)) # zsh
files=(~(N)*.txt) # ksh93
txt がない場合は、空の配列が作成されます コマンドをエラーで失敗させる(または1つの*。txtを含む配列にする)代わりにファイル 他のシェルとのリテラル引数)。
fishのバージョン 2.3より前のバージョンはbash-O nullglobのように機能します ただし、グロブに一致するものがない場合、インタラクティブのときに警告を出します。 2.3以降、 zshのように機能します forで使用されるグロブを除く 、 set またはcount 。
さて、履歴ノートでは、動作は実際には壊れていました ボーンシェルによって。 Unixの以前のバージョンでは、グロブは / etc / globを介して行われました。 ヘルパーとそのヘルパーはcshのように動作しました :どのグロブもどのファイルにも一致しない場合はコマンドに失敗し、それ以外の場合は一致しないグロブを削除します。
したがって、今日の状況は、Bourneシェルで行われた誤った決定によるものです。
Bourneシェル(およびCシェル)には、別の新しいUnix機能である環境が付属していることに注意してください。これは可変拡張を意味しました(前任者には $ 1しかありませんでした 、 $ 2 …位置パラメータ)。 Bourneシェルもコマンド置換を導入しました。
Bourneシェルのもう1つの不十分な設計上の決定は、変数の展開とコマンド置換の際にグロブ(および分割)を実行することでした(おそらく、 echo $ 1であるThompsonシェルとの下位互換性のためです。 それでも/etc / globを呼び出します $ 1の場合 ワイルドカードが含まれていました(展開された値がシェルコードとして再度解析されたため、プリプロセッサマクロの展開に似ていました)。
一致しないグロブが失敗すると、たとえば次のようになります。
pattern='a.*b'
grep $pattern file
コマンドが失敗します( a.whateverbがない場合 現在のディレクトリ内のファイル)。 csh (変数の展開時にグロビングも実行します)その場合、コマンドは失敗します( zsh <のようにグロビングをまったく行わないほど良くない場合でも、休止状態のバグを残すよりはましだと思います。 / code> 。