nullglobがデフォルトではないのはなぜですか?


61

ほとんどのシェルでnullglobはデフォルトではありません。つまり、たとえば、このコマンドを実行すると

ls *

空のディレクトリでは、*globを展開して*、引数の空のリストではなく、リテラルにします。*空のディレクトリで空の引数リストを返すように、その動作を変更する方法があります。これはより直感的に見えるでしょう。

だから、nullglobデフォルトで無効になっている理由はありますか?もしそうなら、その理由は何ですか?


13
かつて誰かが「私たちは常にこの方法でそれをやってきました」に変わった悪い選択をしました。ソフトウェアの世界で非常に遍在する現象(だけでなく)。
PSkocik

4
元々の理由は、nullglobオプションが当時存在していなかったからです。したがって、後方互換性を維持するには、デフォルトで無効にする必要があります。
PM 2Ring

3
null globについては特に言及していませんが、グロビング
StrongBad

4
nullglobをデフォルトで有効にする必要があることは明らかだと思う人もいます。私はそれが明らかだとは思わない。コマンドの呼び出しの前にシェルで展開が行われるということは、何も展開しないことは、グロブが変更されないままでいるほど直感的ではないことを意味します。
小次郎

2
@kojiro誰に直観的ではありませんか?* NIXシェルに精通している人は誰でもそれ*がグロブであることを知っており、既存のすべてファイルに展開します。空のディレクトリグロブがリテラルに「拡張」される特別なケースがあるのは、どのように「直感的」*ですか?
カイルストランド

回答:


78

nullglob(BTWあるオプションzshのみに年後に加え、本発明、bash2.0))は、多くの場合理想的ではないであろう。そしてls良い例です:

ls *.txt

または、より適切な同等物:

ls -- *.txt

nullglob実行します上lsとして扱われる引数なしでls -- .呼び出すよりもおそらく悪いです何のファイルが一致しない場合(カレントディレクトリをリスト)、lsリテラルを*.txt引数として。

ほとんどのテキストユーティリティで同様の問題が発生します。

grep foo *.txt

ファイルfooがない場合は、stdinを探しtxtます。

より賢明なデフォルト、およびcsh、tcsh、zshまたはfish 2.3+(および初期のUnixシェル)の1つは、globが一致しない場合にコマンドを完全にキャンセルすることです。

bash(バージョン3以降)にはfailglobオプションがあります(この議論に興味があるのはash、AT&T kshまたはzshに反して、 bashオプションのローカルスコープをサポートしていないためです(4.4で変更されます)が、グローバルに有効にすると、いくつかのことが壊れますbash-completion関数など)。

cshとtcshはzshfishまたは次のbash -O failglobような場合とわずかに異なることに注意してください。

ls -- *.txt *.html

コマンドをキャンセルするためにすべてのグロブが一致しない必要がある場合。たとえば、1つのtxtファイルがあり、htmlファイルがない場合、次のようになります。

ls -- file.txt

あなたがその動作を得ることができるzshsetopt cshnullglobそれを行うには、より賢明な方法はかかわらzshようグロブを使用することです:

ls -- *.(txt|html)

zshksh93、あなたも適用することができnullglobをグローバル設定を変更するよりも多くの正気のアプローチがあるごとグロブごと、上:

files=(*.txt(N))  # zsh
files=(~(N)*.txt) # ksh93

txtファイルがない場合、エラーでコマンドが失敗する(または*.txt、他のシェルで1つのリテラル引数を持つ配列になる)代わりに、空の配列が作成されます。

fish2.3より前のバージョンは同様に機能しますbash -O nullglobが、グロブに一致するものがない場合に対話型の場合は警告が表示されます。2.3以降、またはでzsh使用されるグロブを除き、同様に機能します。forsetcount

さて、ヒストリーノートでは、この動作は実際にはBourneシェルによって壊れていました。Unixの以前のバージョンでは、グロビングは/etc/globヘルパーを介して行われ、そのヘルパーは次のように動作しました。グロブがcshいずれのファイルにも一致しない場合はコマンドが失敗し、そうでない場合はグロブが削除されます。

したがって、今日の状況は、Bourneシェルで行われた不適切な決定によるものです。

Bourneシェル(およびCシェル)には、別の新しいUNIX機能である環境が付属していることに注意してください。つまり、変数の展開を意味します(前身は$1$2...位置パラメーターのみを持っていました)。Bourneシェルでは、コマンド置換も導入されました。

Bourneシェルの別の貧弱な設計決定は、変数の展開およびコマンド置換でグロブ(および分割)を実行することでした(おそらく、ワイルドカードが含まれている場合にecho $1起動するThompsonシェルとの下位互換性のためです)展開された値がシェルコードとして再度解析されたように))。/etc/glob$1

一致しないグロブの失敗は、たとえば次のことを意味します。

pattern='a.*b'
grep $pattern file

a.whateverb現在のディレクトリにいくつかのファイルがない限り)コマンドは失敗します。csh(変数の展開時にグロビングも実行します)その場合、コマンドは失敗します(そして、のようにグロビングをまったく行わないほど良くない場合でも、休止中のバグをそこに残すよりも良いと主張しますzsh)。


別のユーザビリティの問題がありnullglobます:タブ補完を壊しているようです(有効になっているときにタブキーを押しても何も起こりません)。
カイルストランド

1
それは上のnullglobを使用することが可能ですグロブあたりの構文はzshのほどエレガントではないが- bashの持つ基礎files=$(shopt -s nullglob;echo *.txt)
ジョンNalley

2
@JonNalley。ファイル名の連結(スペースを含む)(可能性のある変換を含むxpg_echo)をスカラー変数に格納します。任意のファイル名で使用できるようにするにはreadarray -td '' files < <(shopt -s nullglob; printf '%s\0' *.txt)bash4.4以上または(shopt -s nullglob; printf '%s\0' *.txt) | xargs -r0 cmdGNUのようなものが必要ですxargs。または、bash4.4で、local -オプションのローカルスコープに(25年後にashからコピーされた)を使用するヘルパー関数を使用します。
ステファンシャゼラス
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.