web-dev-qa-db-ja.com

パターンに一致するファイル名を含むディレクトリの名前を一覧表示するにはどうすればよいですか?

いくつかのサブディレクトリとファイルを含むディレクトリXがある場合、正規表現^rf.*\.img$に一致するファイル名を(直接的または間接的に)含むXの直接の子ディレクトリの名前をリストしたいと思います。

これはOSXでどのように実現できますか?

2
blz

GNU findを使用すると、各ディレクトリをテストできます。

for i in "$dir"/*/
do
    test -n "$(find "$i" -type f -regex '.*/test[^/]*' -print -quit)" \
       && echo "$i"
done

これにより、各ディレクトリでtestで始まるファイルが検索され、見つかった場合はそのディレクトリが出力されます。

注意すべき点がいくつかあります。

  1. .で始まるサブディレクトリは無視しています。それらを考慮する必要がある場合は、.および..をキャッチせずにそれらを含める方法についてBash FAQを確認してください。
  2. 一致する場合は-quitを使用して、findを早期に終了します。これにより、大きなファイルシステムツリーで時間を節約できます。
  3. -regexテストは、findによって考慮されるパス名全体と照合されるため、ベース名と照合するだけの場合は、/との照合に注意する必要があります。 -filenameを使用して、この制限なしで(そして、GNU find)を必要とせずに)ワイルドカードパターンを照合できます。
  4. 大文字と小文字を区別しない一致には、-iregexの代わりに-regexを使用できます。
  5. -regextypeオプションを使用して正規表現構文を選択できます。

質問の特定のパターンについては、ワイルドカードを使用できるため、次のようになります。

for i in "$dir"/*/
do
    test -n "$(find "$i" -type f -name 'rf*.img' -print -quit)" && echo "$i"
done
3
Toby Speight

zshを使用する場合(すでにXにいると仮定):

typeset -U subdirs
subdirs=(*/**/rf*.img(.e_'REPLY=${REPLY%%/*}'_))
print -rl -- "${subdirs[@]}"

ここに */**/rf*.imgすべてのグロブrf*.imgすべてのサブディレクトリ内のファイル、glob修飾子.eは通常のファイルのみを選択し、それぞれ一意の要素を持つ配列として最初に定義された配列のパスの最初のコンポーネントのみを保存します(したがって重複はありません)。次に、配列の各要素を出力します。

2
don_crissti

find を使用してリストを取得し、それを grep にパイプすることができます。

(cd X && find . -type d -maxdepth 1 | sed -e 's,^./,,' | grep -E '^rf.*\.img$' )

サブシェルを使用して、X内の名前だけを取得しました。それ以外の場合は、findのパスを考慮する必要があります。

サブディレクトリが再帰的に必要な場合は、-maxdepth 1オプションを省略できます。しかし、それはあなたが正規表現を調整しなければならないことを意味します、例えば、

(cd X && find . -type d | sed -e 's,^./,,' | grep -E '^(.*/)?rf.*\.img$' )

その場合、sedコマンドは冗長です(ただし無害です)。

1
Thomas Dickey

greplsも使用せず、findを使用します。

find . -name 'rf*.img'

GNU findには、ディレクトリのみを出力するオプションがあります(-printf "%h\n")しかし、あなたの場合、それはオプションではありません。

あなたは次のようなことをすることができます:

find . -name 'rf*.img' | sed 's:/[^/]*$::'

最初のディレクトリだけが必要な場合は、次のようになります。

find . -name 'rf*.img' -exec dirname {} \; | sed 's:./\([^/]*\).*:\1:'
1
muru

Perlとそのgrepおよびglobを使用します。

#!/usr/bin/env Perl
use strict;
use warnings;

my @file_list = grep { /^rf.*\.img$/ } glob "*";
print join ( "\n", @file_list );

またはワンライナーとして:

Perl -e 'print join ( "\n", grep { /^rf.*\.img$/ } glob "*" )'

注-globはシェルスタイルのワイルドカード拡張を行うため、glob "*/*/name/*"または同様のものを使用できます。任意の再帰深度が必要な場合は、代わりにFile::Findを使用することをお勧めします。

#!/usr/bin/env Perl
use strict;
use warnings;

use File::Find;

sub print_match {
    #Default match is against $_ which is filename. 
    #can match $File::Find::name for full name.
    #or $File::Find::dir
    print if  /^rf.*\.img$/;
}

find ( \&print_match, "/path/to/search" );

再びワンライナーとして:

Perl -MFile::Find -e 'find ( sub { print if  /^rf.*\.img$/ }, "/my/path/to/search" );'
0
Sobrique