**/*.ext
は*.ext
に一致するすべてのサブディレクトリ内のすべてのファイルに展開することを知っていますが、currentディレクトリ内のすべてのそのようなファイルを含む同様の展開は何ですか?
これは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倍になりました。
これは、「。ext」で終わる現在のディレクトリとそのサブディレクトリ内のすべてのファイルを印刷します。
find . -name '*.ext' -print
**/*.*
を使用して、すべてのファイルを再帰的に含めることができます(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 dotglob
(shopt -u dotglob
で無効化)を使用します。 mv
やrm
などのコマンドに影響を与える可能性があり、誤って誤ったファイルを削除する可能性があるため、お勧めしません。
現在のディレクトリも含めるためにブレース拡張を使用しないのはなぜですか?
./{*,**/*}.ext
ブレースの展開は、グロブの展開の前に行われるため、古いバージョンのbashで必要なことを効果的に行うことができ、新しいバージョンではglobstarでのサル化を避けることができます。
また、bashでは、先頭の./
をglobパターンに含めることをお勧めします。
$ find . -type f
これにより、現在のディレクトリ内のすべてのファイルがリストされます。その後、-execを使用して、出力に対して他のコマンドを実行できます
$find . -type f -exec grep "foo" {} \;
文字列「foo」の検索から各ファイルをgrepします。