ackを含むパターンに一致するファイルのみを検索する


49

特定の「glob」パターンに一致するファイルのみを検索できます(例:「bar * .c」という名前のすべてのファイルでfooを検索します)。コマンド

ack foo "bar*.c"

現在のディレクトリでのみ機能します。

注:find -execを使用すると可能だとわかっています。

find . -name "bar*.c" -type f -exec ack foo {} + 

ただし、findはバージョン管理ディレクトリをスキップしないため、小さくシンプルなackコマンドが必要です。


2
私は理解していません、使用の何が問題なのfind . -name "bar*.c" -exec ack foo {} \;ですか?特別なことgrepは何もありません。findで任意のコマンドを使用できます-exec
テルドン

1
@terdon findはバージョン管理ディレクトリも検索しますが、これは望ましくありません。
compie

2
次に、質問を編集して、回避する必要がある制限を説明してください。
テルドン

回答:


28

ディレクトリを検索する

マニュアルページに示されている概要に基づいて、ディレクトリを処理することはできますが、スイッチを見ると、パターンに基づいたファイルだけを検索することはできません。そのためには、入隊する必要がありますfind。コマンドackにはオプションが含まれている--files-from=FILEため、ファイルのリストをから提供できますfind

あらすじ

       ack [options] PATTERN [FILE...]
       ack -f [options] [DIRECTORY...]

使用法

   --files-from=FILE
       The list of files to be searched is specified in FILE.  The list of
       files are separated by newlines.  If FILE is "-", the list is
       loaded from standard input.

--ignore-file=あなたが望むものをあなたに与えるかもしれないオプションがありますが、実際に使用するのは少し苦痛のようです。

   --ignore-file=FILTERTYPE:FILTERARGS
       Ignore files matching FILTERTYPE:FILTERARGS.  The filters are
       specified identically to file type filters as seen in "Defining
       your own types".

特定の種類のファイルを検索する

私がこれを行うことを想像できる唯一の他の方法ackは、その--typeスイッチを使用することです:

   --type=[no]TYPE
       Specify the types of files to include or exclude from a search.
       TYPE is a filetype, like perl or xml.  --type=perl can also be
       specified as --perl, and --type=noperl can be done as --noperl.

       If a file is of both type "foo" and "bar", specifying --foo and
       --nobar will exclude the file, because an exclusion takes
       precedence over an inclusion.

利用可能なタイプを確認するには:

$ ack --help-types | grep -E "perl|cpp"

フォーマット。たとえば、-type = perlと--perlの両方が機能します。-[no] cpp .cpp .cc .cxx .m .hpp .hh .h .hxx-[no] objcpp .mm .h-[no] perl .pl .pm .pod .t .psgi; 最初の行は/^#!.*\bperl/-[no] perltest .tに一致します

ファイル名(* .pm、*。pl、*。t、*。pod)とshebang行の両方に基づいて、すべてのPerlファイルを見つけます。

$ ack -f --type perl 
examples/iwatch/iwatch/iwatch
examples/nytprof_perl/bad.pl

すべてのC ++ファイルを検索します。

$ ack -f --type=cpp
Shared/Scanner.h
Shared/Sorter.h
Shared/DicomHelper.cpp
Shared/DicomDeviationWriter.h

bar * .cでfooを検索する

それでは、どうすれば自分の望むことを達成できますか?さて、あなたはおそらくfindこれを行うために使用する必要があります:

$ find adir -iname "bar*.c" | ack --files-from=- foo
adir/bar1.c
1:foo
2:foo

adir/dir1/bar1.c
1:foo
2:foo

またack、ファイル名で特定のパターンに一致するファイルを検索する機能を使用して(を使用-g <pattern>)、このリストをackusing -xまたは--files-from=-..の2回目の呼び出しに渡すこともできます。

を使用して-x

$ ack -g '\bbar.*.c$' | ack -x foo
bar1.c
1:foo
2:foo

dir1/bar1.c
1:foo
2:foo

を使用して-files-from=-

$ ack -g '\bbar.*.c$' | ack --files-from=- foo
bar1.c
1:foo
2:foo

dir1/bar1.c
1:foo
2:foo

いずれの場合でも、この正規表現を使用して、必要なファイル名を照合します。

\bbar.*.c$

これはbar.*c、行末.cアンカーを使用した後に名前がで終わるファイルに一致します$。また、を使用して、名前に境界文字が含まれていることを確認し\bます。これは、次のような境界文字を含むファイルに対して失敗する$bar.cか、%bar.c例えば。


1
これは私の質問に答えません(「bar * .c」という名前のすべてのファイルでfooを検索します)
compie 14

1
@compie-必要なファイルのスライスを取得する方法を示しているという意味では、そうです。cppファイルを検索するにはack --type=cpp <string>ackただし、これらすべての詳細については、のmanページをご覧ください。しかし、私が基本的にあなたに言っているのは、あなたがack望む方法で検索できないということです。
slm

1
そのため、ack要求された内容を実行できないことを示すという意味で回答します。
xealits 14

@xealits-この部分は答えます:bar * .cでfooを検索します find adir -iname "bar*.c" | ack --files-from=- foo。または、1つのファイルだけが必要な場合:echo "barBaz.c" | ack --files-from=- foo
alexanderbird

2
tldr; ack -g '\bbar.*.c$' | ack -x foo
チム

14

ファイルの種類がわかっていれば簡単で、ackは多くのファイルの種類を知っています。したがって、たとえば、Cファイルでのみ検索したい場合は、次のようにします。

ack --cc 'string'

ただし、既知の拡張機能のいずれでもない場合は、独自のタイプを定義する必要があります。これは動作するはずです:

ack --type-set barc:match:/bar.+\.c/ --barc 'string'

--type-setと--barcの両方が必要なことに注意してください。

(メーリングリストでこれを手伝ってくれたAndyに感謝します。)


1
うまくいきますが、findと 'ack -x'を使用する方が簡単です。私はそれに固執すると思います。
compie 14

ここにドキュメントへのリンクを追加すると役立ちます。man ack本当に助けにならずcc、私がそれを検索するときに持っていません。
YPCrumble

ack --help = types考えられることは何でもあります。主にPythonとAdaに使用します。
デビッドボッシュトン

6

「ack 2の新機能」http://beyondgrep.com/ack-2.0/

ack 2.0では、新しい-xを使用して、ackの呼び出しから別の呼び出しへファイル名をパイプできます。

ack2 -g -i filepattern | ack2 -x -w searchpattern

動作させることができないのは私だけです:

% ack -g "*bar*.c"
Invalid regex '*bar*.c':
Quantifier follows nothing in regex; marked by <-- HERE in m/* <-- HERE bar*.c/ at ack line 314.

したがって、-gには正規表現が必要ですが、「glob」スタイルのオプションが必要です...


2
はい、-gグロブではなく正規表現を使用します。あなたの正規表現をとして書くことができます.*bar.*\.c$
アンディレスター14

2
@AndyLester確認いただきありがとうございます。ackの「glob」オプションのアイデアが好きですか?
compie

3

これは最速かつ最も安全なようです:

find . -name '*.c' | ack -x 'some string'

-x STDINから検索するファイルのリストを読み取ります。

ただし、ファイルがlocateデータベースにある可能性が高い場合、これはさらに高速になります。

locate --basename '*.c' | ack -x 'some thing'

Locateは昔ながらの正規表現を受け入れることもできますが、少し苦痛ですが、cファイルを探している場合は必要になるかもしれません。 例えば

locate --basename --regexp '\.\(c\|cpp\|h\|hpp\|cc\)$' |
    ack -x 'some thing'

これは、「c、cpp、h、hpp、またはccで終わるすべてのファイル名を検索する」に変換されます。


2

Ackは、globスタイルのファイル選択をサポートしていません。これが本当に恋しいので、小さなシェルスクリプトackgを作成しました。

#!/bin/sh
# 'glob' support for ack
find -name "$2" -type f -exec ack "$1" {} +

これで、次のコマンドを使用できます。

ackg foo "bar*.c"

ただし、これは残念ながらバージョン管理ディレクトリ(例:.git)でも検索します。


2

これは、シルバーサーチャー(ack-grepの拡張クローン)の-Gオプションを使用して実行できます。

$ echo foo > bar_wanted.c
$ echo foo > unwanted.c
$ ag -G "bar.*\.c" foo
bar_wanted.c
1:foo

ノート:

  • agPCRE正規表現構文を使用しているため、正規表現はのbar.*\.c代わりにする必要がありbar*.cます。
  • -Gオプションはファイル名として解釈され、その後何として、検索語に先行する必要があります。

1

特定のパターンだけが必要ですか、それともCソースファイルだけが必要ですか?

すべてのCファイルが必要な場合は、使用します

ack --cc foo

CヘッダーファイルではなくすべてのCファイルが必要な場合は、

ack --cc --no-hh foo

1

@chimの答えは最高ですが、コメントとして書かれているので、正式な答えとして再投稿しています...

ack -g '\bbar.*.c$' | ack -x foo

私はあなたがパスを正規表現できるという事実が好きです...


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