web-dev-qa-db-ja.com

現在のディレクトリ内のすべてのファイルに再帰的に拡張されるものは何ですか?

**/*.ext*.extに一致するすべてのサブディレクトリ内のすべてのファイルに展開することを知っていますが、currentディレクトリ内のすべてのそのようなファイルを含む同様の展開は何ですか?

86
Ramon

これはBash 4で機能します:

ls -l {,**/}*.ext

ダブルアスタリスクのグロブを機能させるには、globstarオプションを設定する必要があります(デフォルト:オン):

shopt -s globstar

man bashから:

 globstar 
設定されている場合、ファイル名展開con ‐ 
テキストで使用されるパターン**は、ファイルおよびゼロ個以上のディレクトリおよび
サブディレクトリと一致します。パターンの後に/が続く場合、
ディレクトリとサブディレクトリのみが一致します。

今は単にls **/*.extを使用しているので正しい結果が得られるため、globstar処理にバグがあったのではないかと思っています。

とにかく、私は analysis kenorbがVLCリポジトリを使用して行ったことを見て、その分析でいくつかの問題を見つけました。

findコマンドの出力との比較は無効です。これは、-type fの指定に他のファイルタイプ(特にディレクトリ)が含まれておらず、リストされているlsコマンドが含まれている可能性が高いためです。また、リストされているコマンドの1つであるls -1 {,**/}*.*-これは上記のものに基づいているように見えますが、サブディレクトリにあるファイルの名前を含むのみを出力します。求められているのは特定の拡張子を持つファイルであるため、OPの質問と私の答えにはドットが含まれています。

ただし、最も重要なのは、グロスターパターン**lsコマンドを使用すると特別な問題があることです。パターンがBashによって検査中のツリー内のすべてのファイル名(およびディレクトリ名)に展開されるため、多くの重複が発生します。展開に続いて、lsコマンドは、eachとそれらがディレクトリである場合はその内容をリストします。

例:

現在のディレクトリには、サブディレクトリAとそのコンテンツがあります。

A
└── AB
    └── ABC
        ├── ABC1
        ├── ABC2
        └── ABCD
            └── ABCD1

そのツリーでは、**は「AA/AB A/AB/ABC A/AB/ABC/ABC1 A/AB/ABC/ABC2 A/AB/ABC/ABCD A/AB/ABC/ABCD/ABCD1」に展開されます"(7エントリ)。 echo **を実行すると、正確な出力が得られ、各エントリが1回だけ表示されます。ただしls **を実行すると、のリストが出力されますエントリ。したがって、本質的にはls Aに続いてls A/ABなどが実行されるため、A/ABは2回表示されます。また、lsは各サブディレクトリの出力を区別します:

...
<blank line>
directory name:
content-item
content-item

そのため、wc -lを使用すると、すべての空行とディレクトリ名セクションの見出しがカウントされ、さらにカウントがスローされます。

これは、 parse ls をすべきではないもう1つの理由です。

このさらなる分析の結果として、この方法でファイルのツリーを反復処理する以外の状況では、globstarパターンを使用しないことをお勧めします。

for entry in **
do
    something "$entry"
done

最後の比較として、手元にあるBashソースリポジトリを使用してこれを行いました。

shopt -s globstar dotglob
diff <(echo ** | tr ' ' '\n') <(find . | sed 's|\./||' | sort)
0a1
> .

名前にスペースが含まれていないため、ここでのみ有効な改行にスペースを変更するためにtrを使用しました。 sedからの出力の各行から先頭の./を削除するためにfindを使用しました。 findの出力は通常ソートされず、Bashのglobの展開はすでにソートされているため、ソートしました。ご覧のとおり、diffからの唯一の出力は、現在のディレクトリ.によるfindによる出力です。 ls ** | wc -lを実行すると、出力の行がほぼ2倍になりました。

102

これは、「。ext」で終わる現在のディレクトリとそのサブディレクトリ内のすべてのファイルを印刷します。

find . -name '*.ext' -print
12
unutbu

**/*.*を使用して、すべてのファイルを再帰的に含めることができます(shopt -s globstarで有効化)。

以下に、他のバリエーションのテストとその動作を見つけてください。


サンプル内の3472ファイルのテストフォルダー [〜#〜] vlc [〜#〜] リポジトリフォルダー:

(合計で3472個のファイルをカウント:find . -type f | wc -l

  • ls -1 **/*.*-3338を返します
  • ls -1 {,**/}*.*-3341を返します( Dennis によって提案されたとおり)
  • ls -1 {,**/}*-8265を返します
  • ls -1 **/*-7817を返します。ただし、隠しファイルは除きます( Dennis によって提案されたとおり)
  • ls -1 **/{.[^.],}*-7869を返します( Dennis によって提案されたとおり)
  • ls -1 {,**/}.?*-15855を返します
  • ls -1 {,**/}.*-20321を返します

したがって、すべてのファイルを再帰的にリストする最も近い方法は、 gniourf-gniourf comment (ファイルに適切な拡張子があるか、特定の拡張子を使用する場合)の最初の例(**/*.*)であると思います)、2番目の例では、以下のような重複はほとんどありません。

$ diff -u <(ls -1 {,**/}*.*) <(ls -1 **/*.*)
--- /dev/fd/63  2015-04-19 15:25:07.000000000 +0100
+++ /dev/fd/62  2015-04-19 15:25:07.000000000 +0100
@@ -1,6 +1,4 @@
 COPYING.LIB
-COPYING.LIB
-Makefile.am
 Makefile.am
@@ -45,7 +43,6 @@
 compat/tdestroy.c
 compat/vasprintf.c
 configure.ac
-configure.ac

もう一方はさらに複製を生成します。


隠しファイルを含めるには、shopt -s dotglobshopt -u dotglobで無効化)を使用します。 mvrmなどのコマンドに影響を与える可能性があり、誤って誤ったファイルを削除する可能性があるため、お勧めしません。

6
kenorb

現在のディレクトリも含めるためにブレース拡張を使用しないのはなぜですか?

./{*,**/*}.ext

ブレースの展開は、グロブの展開の前に行われるため、古いバージョンのbashで必要なことを効果的に行うことができ、新しいバージョンではglobstarでのサル化を避けることができます。

また、bashでは、先頭の./をglobパターンに含めることをお勧めします。

3
clone206
$ find . -type f

これにより、現在のディレクトリ内のすべてのファイルがリストされます。その後、-execを使用して、出力に対して他のコマンドを実行できます

$find . -type f -exec grep "foo" {} \;

文字列「foo」の検索から各ファイルをgrepします。

3
Amir Afghani