再帰的なグロブ?


80

私はこのような何かを書きたいです:

$ ls **.py

すべての.pyファイル名を取得するために、ディレクトリ階層を再帰的にたどります。

検索する.pyファイルがある場合でも、シェル(bash)は次の出力を提供します。

ls: cannot access **.py: No such file or directory

私がしたいことをする方法はありますか?

編集:の特定のケースに興味がないことを指定したいのですlsが、問題はglob構文に関するものです。

回答:


98

bashで再帰的なglobを実行するにはglobstar、bashバージョン4以降の機能が必要です。

bashのマンページから:

globstar
    If set, the pattern ** used in a pathname expansion context will
    match all files and zero or more directories and subdirectories.
    If the pattern is followed by a /, only directories and
    subdirectories match.

サンプルパターンの場合:

shopt -s globstar
ls **/*.py

2
また有効にすることをお勧めしますnullglob
グレンジャックマン

6
@glennjackmanしかし、有効にする前にnullglob、次の警告を読むことを強くお勧めします
セルジュストローバンド

2
^警告はここに移動しました
-usandfriends

1
bash 3.2では、wc -l {**,.}/*.pyうまく動作します
ラファエル

@Raphaelリリースノートを再確認したところ、4.0で導入されたことが明確に示されています。おそらくあなたのディストリビューションはパッチをバックポートしていますか?IIRC RHEL 5はいくつかの機能をバックポートしていました。また、bash 4がリリースされてから9年が
経ちました...-ヨルダン

10
find . -name '*.py'

** 1つ以上のことは行いません*、両方とも現在のディレクトリで動作します


面白い。ただし、構成ファイル(includeディレクティブ)でglob構文を使用する必要があるため、glob構文のみに焦点を当てています。ファイルのリストは必要ありません。
パオロ

2
@Doug O'Neal、それはもはや真実ではありません。bashは今(それが近づいは、ksh93のとkshのようなものに構文を採用してもzshののグロブ修飾子をサポートしていない、まだその有用性を制限する)zshの機能というコピーした
ステファンChazelas

findbash 4を持っていない場合にできることはたくさんあります。例:(yourcommand `find . -name '*.py'`バッククォートに注意してください); find . -name '*.py' -exec yourcommand {} \;
火星

5

Bash 4(zshも含む)以降、新しいグロビングオプションglobstar)が追加され、**設定時にパターンを異なる方法で処理します。

ワイルドカードパターンと一致し、コマンド内のワイルドカードパターンを一致したアイテムで置き換えることにより、一致するファイル名とディレクトリ名を返します。

通常、を使用する場合**、と同様に機能しますが*、すべてのディレクトリを再帰的に再帰します(ループのように)。

有効になっているかどうかを確認するにはshopt globstar、スクリプトで確認します(使用するにはを使用しますshopt -q globstar)。

この例**.pyは、再帰可能なディレクトリのリストを返さないため、現在のディレクトリでのみ機能します**/*.py。そのため、複数のディレクトリレベルのワイルドカードを使用する必要があるため、さらに深くすることができます。

すべてのファイルを再帰的に見つけるために行ったいくつかの構文テストを見つけてください。

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