.txtファイルが存在しない場合、シェルで* .txtを使用した拡張は機能しません


10

私は拡張機能をいじっていましたが、奇妙な動作に気づきました。私はやってみました:

echo ./*.txt

また、現在のディレクトリに.txtファイルがありませんでした。私が得た出力は:

./*.txt

私はただ興味があります。なぜこれを取得したのですか?出力が得られないと予想していました。

PS:.txtファイルがあるとき、拡張は正しく解釈されました。言い換えれば、私がファイルを持っていると言うとsmthn.txt、エコーは実際にエコーされましたcurrent_directory/smthn.txt

回答:


15

bashシェルのmanページから適応し、

bashは、*、?、および[の各文字をスキャンします。これらの文字のいずれかが表示される場合、その単語はパターンと見なされ、パターンに一致するファイル名のアルファベット順にソートされたリストに置き換えられます。一致するファイル名が見つからず、シェルオプションnullglobが有効になっていない場合、単語は変更されません。nullglobオプションが設定されていて、一致するものが見つからない場合、単語は削除されます。

この場合、nullglobが有効になっていないと想定しているため、単語は変更されないままなので、出力が表示されます。


2
次のように動作を変更できます。shopt -s nullglob一致しないパターンに対して空の文字列を生成し、shopt -u nullglob(標準設定)はパターン自体を生成します。
PerlDuck

13

出力が得られないと予想していました。

Ifはnullglobデフォルトだった、(おそらく残念ながら)コマンドがある場合扱うのが一般的であるため、多くのコマンドは、全く予想外振る舞うゼロの場合よりも質的に異なる方法でファイル名の引数を一つ以上のファイル名の引数を指定します。

nullglobshopt -s nullglob)を有効にし、一致するファイルがないディレクトリにいるとします*.txt。その後、*.txt実際には何も展開しません。空のフィールドではなく、フィールドはまったくありません。しかし、その結果は次のようになります。

  • ls *.txt現在のディレクトリにあるすべてのファイル(隠しファイルを除く)を一覧表示しますls。これは、ファイル名引数を渡さない場合に行われるためです。
  • cat *.txtがファイル名引数を持たない場合は、実行したかのように、標準入力から読み取りcatますcat -。インタラクティブに実行している場合は、入力を待機しています。多くのコマンドはこのように動作します。
  • cp *.txt dest/エラーで失敗しますcp: missing destination file operand after 'dest/'。これは災害ではありませんが、混乱を招き、おそらく望ましいサイレント成功とはかなり異なります。
  • file *.txt、およびファイル名引数がゼロの場合に特別な動作を行わない他のさまざまなプログラムは、何も渡されない場合でもエラーまたは使用法メッセージで失敗します。
  • 直感的に機能するはずであると感じるケースでも、多くの場合機能しません。何もprintf 'Got file: "%s"\n' *.txt印刷するGot file: ""代わりに印刷します。
  • 不慮の出来事を引用するのに失敗*?されていないシェルによって展開されることを意図し、より多くの場合、明らかに間違った結果を生むだろうが、把握するのが難しいかもしれない方法インチ たとえば、現在のディレクトリにで始まるファイル名がない場合、(意図されていた場所で)が正しくなり使用可能なすべてのパッケージがリストされます。[geditapt list gedit*apt list 'gedit*'apt list

したがって、要求しないとこの動作が発生しないのは良いことです。おそらく実際に単純化される最も一般的な実際の状況nullglobfor f in *.txtです。この質問も参照してください(Sergiy Kolodyazhnyyの回答にリンクされています)。

答えるのが難しい質問は、failglobどのファイルにも一致しないグロブがあると展開エラーになるのに、bashのデフォルトではない理由です。Sergiy Kolodyazhnyyの回答は、直接対処しなくても、この理由を捉えていると思います。展開エラーを生成せずに展開されていないグロブを保持することは、(おそらく残念なことに)標準化された動作であり、これも従来の動作であり、したがって期待される動作です。bashは、名前を指定して呼び出されるshか、--posixオプションを渡さない限り、完全にPOSIXに準拠しようとはしませんが、POSIXモードでない場合でも、設計の選択肢の多くはPOSIXに直接従います。彼らはいくつかの行動を選ぶ必要があり、ユーザーの期待に反することに関連する欠点があります。


これは最も歴史的に影響の少ない問題だと思うので、最後に保存しておきますが、nullglob動作については概念的に少し奇妙な点があることに言及する価値があります。

nullglob構文的には、一致するファイルゼロの場合も1、2、またはその他の数の場合と同じように扱われるため、最初はエレガントに見えます。上で詳述したように、グロブが引数に展開される、実行するコマンドは同じように処理する傾向ありません。しかし、構文的にはこれは少なくとも正しいと感じます。これがあなたの質問の動機だと思います。

それでも、nullglob対処できない別のより微妙な不整合があります-それは実際に増幅します。ゼロのグロビング文字(「ワイルドカード」)の場合は、1つ、2つ、またはその他の数字の場合とは大きく異なります。たとえば、ではshopt -s nullglobab?d?fどのファイルとも一致しない場合は削除されます。ab?dどのファイルとも一致しない場合は削除されます。ただし、abどのファイルとも一致しない場合(つまり、名前が正確にのファイルがない場合ab)は、削除されません。もちろん、現在のディレクトリにある既存のファイルを参照することをまったく意図していない可能性があるため、削除した場合は問題になります。ファイルを参照しないこともあります。しかし、これはまだ完全な一貫性への希望を排除します。

bashが提供する3つの動作-ファイルに一致しないグロブをグロブではないかのように扱い、展開せずに渡すデフォルト、それらを処理することで期待される動作(この奇妙なフレーズのターンを許す場合)一致するファイルのすべてのゼロ(nullglob)と、それらをエラーと見なす安全な動作()を意味します。これらはfailglobすべて、特定の単語がファイル名。シェルは、それを使用して呼び出す特定のコマンドが引数をどのように処理するかを認識せずに、展開を実行します。

これは、懸念分離の多くの例の1つです。Unixの哲学に従って設計されたシステムでは、各部分は1つのことを行い、それをうまく行うことを目的としています。シェルはテキストをコマンドと引数に処理し、それらのコマンドを呼び出します。これらのコマンドのほとんどはシェル自体の外部にあります。これは、外部コマンド自体が(DOSやWindowsの従来のコマンドプロセッサのように)これらの変換を実行する責任があるシステムよりも優れており、用途が広い傾向があります。しかし、それはその時々の欠点があります。


どうやら、bash-4.3.39(2)にはがありませんfailglob。したがって、常にサポートされているわけではないため、デフォルトにすることはできません。
ルスラン

6

主な理由は、これがPOSIXによって指定された標準の動作であり、シェルコマンド言語やその他のパタ​​ーンマッチング(シェルbashdashUbuntuのデフォルトなどのシェル/bin/sh、およびkshこの標準に従う)をカバーする標準だからです。セクション2.13.3から、ファイル名拡張に使用されるパターン

パターンが既存のファイル名またはパス名と一致しない場合、パターン文字列は変更されません。

もちろん、これには文字通りの副作用と一致するファイル名があります*.txtnullglob内のオプションbashzsh缶ヘルプ:そのオプションを経由して有効になっている場合shopt -s nullglob(そしてそれはこの質問に適用され、デフォルトでは有効になっていません)、一致するファイル名が見つからないときにglobstar空の文字列に展開されます。ksh93同じ効果を実現する独自の高度なパターンマッチングメカニズム~(N)*.txt

nullglobがデフォルトではない理由も参照してください

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.