空の文字列が現在のディレクトリを示すのはいつですか?

空の文字列が現在のディレクトリを示すのはいつですか?

find現在のディレクトリ内のいくつかのファイルを収集するために使用するスクリプトでは、

$ find . -name "*.h"
./foo.h

foo.hここで、プレフィックスなしでだけを出力したいと思います./。空の文字列は""シェル コマンドの現在のディレクトリを表すものだと思っていました。しかし、次のようになります。

$ find "" -name "*.h"
find: ftsopen: No such file or directory

つまり、私は間違っていました。ここでの質問は、ファイル名またはパス名を期待するコマンドで、「空の文字列 (?)」が現在のディレクトリを示すのはいつ、どのように、どこで、または... かということです。わかりやすくてわかりやすい説明はありますか?

${parameter#word}副次的な質問ですが、上記の細かい点を見つける問題は、やcutのような文字列操作を行わずに、簡単に解決できるのでしょうかsed?

答え1

昔々( 第7版32V4.2BSD4.3BSD)、システムコールレベルでは、長さがゼロのパス名は現在の作業ディレクトリを示していました(検索に使用された場合。ファイルやディレクトリを作成または削除しようとする場合は許可されませんでした)。 システムIIIいかなる状況でも長さゼロのパス名を使用することはエラーであり、POSIX標準パス名の解決については次のように述べています。

ヌルパス名は正常に解決されません。

答え2

以下を使用できます:

find * -name "*.h"

現在のディレクトリ内で名前が で始まるファイルは.省略され、名前が で始まるファイルは-および によってオプションとして解釈されfind、混乱を引き起こすため、これは と一般的に同等ではないことに注意してくださいfind . …

/ファイル名に「 」で終わる文字列が含まれていない暗示する現在のディレクトリですが、現在のディレクトリが表記空の文字列によって表されます (文字列が存在しない状態と同じではないと言えますが、印刷すると同じに見える場合があります)。

答え3

一般に、空の文字列は、シェル コマンドでもシステム コールでも、現在のディレクトリを示すものではありません。一部の古いシステムでは可能でしたが、POSIX準拠のシステムでは不可能でした。

時々、空の文字列を渡し、プログラムがディレクトリ名を期待しているときに、現在のディレクトリを使用するプログラムが見つかることがあります。これは意図的な場合もあれば、指定された文字列がスラッシュで始まっていない場合に現在のディレクトリの絶対パスを先頭に追加することによる副作用である場合もあります。

あなたにとって最善の策は、 を離れることです./。害はありません。

ファイルのリストが

find . … | sed 's!^\./!!'

これにより、改行を含むファイル名が一部変形されることに注意してください。これは通常、人間が使用する場合には問題にはなりませんが、 の出力はfindあいまいであるためプログラムで使用するには適していません。プログラム-print0で使用するのに適した を使用している場合は、プレフィックスを気にする必要はないでしょう./

find * …の代わりにを使用することもできますfind . …が、 にfind *はいくつかの欠陥があり、一般には適さないことに注意してください。

  • .省略されます。
  • すべてのドットファイル(名前が.または ..` で始まるファイル)は省略されます。
  • 現在のディレクトリに で始まるファイル名(またはまたは... と-呼ばれるファイル) がある場合、 によってオプションまたは述語として解釈されます。!(find

最初のポイントは、フィルターが現在のディレクトリを除外する場合は問題になりません。2 番目のポイントについては、パターンを使用して..?* .[!.]* *現在のディレクトリ内のすべてのファイルに一致させることができますが、各パターンが少なくとも 1 つのファイルに一致するかどうかを確認し、一致しない場合は省略する必要があります。これは可能ですが、非常に面倒です。最後のポイントはストッパーです。そのため、find *簡単なコマンド ラインの使用には適しているかもしれませんが、スクリプトでは使用しないでください。

別の方法としては、シェルの再帰グロブ機能を使う方法があります。例えば、

printf '%s\n' **/*.h

shopt -s globstarこれは、bash ではによって、ksh93 では によってアクティブ化される必要がありset -o globstar、dash などの基本的な POSIX シェルには存在しません。ドット ファイルはデフォルトでは走査されません。ドット ファイルを含めるには、まず、shopt -s dotglobbash またはFIGNORE='@(.|..)'ksh93 でグロビングがドット ファイルを無視しないようにします。また、一致するものがない場合、このコマンドはパターンを出力します。代わりに空の行を出力するには、bash で を実行し、 ksh でshopt -s nullglobパターンを使用します。~(N)**/*.h

Dzshでは、再帰的なグロブはデフォルトでオンになっています。ドットファイルを含め、一致しない場合は空行を出力するには、 glob修飾子を使用しますN(デフォルトでは、パターンがどのファイルにも一致しない場合はzshはエラーをスローします)。printf上記のように使用するか、

print -rl -- **/*.h(DN)

答え4

先頭の なしで find の出力を取得するために使用できるさまざまなトリックがあります./:

  1. find の-printfオプションを使用して、印刷のみを指示します%f。参照man find:

    %f 先頭のディレクトリが削除されたファイル名 (最後の要素のみ)。

    例えば:

    find . -name "*.h" -printf "%f\n"
    
  2. 出力を解析します。

    find . -name "*.h" | sed 's#^./##'
    
  3. @アンソンのトリック

    find * -name "*.h"
    

他の質問に関して言えば、空の文字列は現在のディレクトリを示すことはありません。さまざまなプログラムが現在のディレクトリをデフォルトとして受け入れるため、引数なしで実行すると、現在のディレクトリで実行されます。

関連情報