Suchen Sie nur in Dateien, die einem Muster mit ack entsprechen


49

Kann nur Dateien durchsuchen, die einem bestimmten 'Glob'-Muster entsprechen (zB: Suche nach foo in allen Dateien mit dem Namen "bar * .c"). Der Befehl

ack foo "bar*.c"

Funktioniert nur im aktuellen Verzeichnis.

Hinweis: Ich weiß, dass es mit find -exec möglich ist:

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

Ich hätte aber gerne einen kleinen und einfachen Befehl ack, da find keine Verzeichnisse zur Versionskontrolle überspringt.


2
Ich verstehe nicht, was ist falsch daran find . -name "bar*.c" -exec ack foo {} \;? Es gibt nichts Besonderes grep, Sie können jeden Befehl mit find's verwenden -exec.
Terdon

1
@terdon find durchsucht auch Versionskontrollverzeichnisse und das möchte ich nicht.
Compie

2
Bearbeiten Sie dann Ihre Frage und erläutern Sie die Einschränkungen, die Sie umgehen müssen.
Terdon

Antworten:


28

Verzeichnisse durchsuchen

Basierend auf der in der Manpage gezeigten Übersicht würde ich sagen, dass es ein Verzeichnis verarbeiten kann, aber wenn man sich die Schalter ansieht, kann es nicht nur nach einer Datei suchen, die auf einem Muster basiert. Dafür musst du dich anmelden find. Der Befehl ackenthält die Option, --files-from=FILEdamit ihm eine Liste von Dateien zugeführt werden kann find.

Zusammenfassung

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

Verwendungszweck

   --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.

Es gibt die --ignore-file=Option, die Ihnen vielleicht das gibt, was Sie wollen, aber es scheint ein bisschen mühsam zu sein, sie tatsächlich zu nutzen.

   --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".

Durchsuchen bestimmter Dateitypen

Die einzige andere Möglichkeit, die ich mir vorstellen kann, ackist die Verwendung des --typeSchalters:

   --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.

So sehen Sie, welche Typen verfügbar sind:

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

Format. Beispielsweise funktionieren sowohl --type = perl als auch --perl. - [no] cpp .cpp .cc .cxx .m .hpp .hh .h .hxx - [no] objcpp .mm .h - [no] perl .pl .pm .pod .t .psgi; Die erste Zeile entspricht /^#!.*\bperl/ - [no] perltest .t

Beispiele

Suchen Sie alle Perl-Dateien anhand des Dateinamens (* .pm, * .pl, * .t und * .pod) und der Shebang-Zeile.

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

Finden Sie alle C ++ - Dateien:

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

Suche nach foo in bar * .c

Wie können Sie dann erreichen, was Sie wollen? Nun, Sie müssen wahrscheinlich verwenden find, um dies zu tun:

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

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

Sie können mit der Funktion von auch acknach Dateien suchen, die mit einem bestimmten Muster in ihren Dateinamen übereinstimmen (mithilfe von -g <pattern>), und diese Liste dann an einen zweiten Aufruf von ackusing -xoder übergeben --files-from=-.

Verwenden von -x:

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

dir1/bar1.c
1:foo
2:foo

Verwenden von -files-from=-:

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

dir1/bar1.c
1:foo
2:foo

In beiden Fällen stimmen wir mit den Dateinamen überein, die Sie mit diesem regulären Ausdruck verwenden möchten:

\bbar.*.c$

Dies entspricht Dateien , dessen Namen bar.*cund das Ende nach der .cdas Ende der Linie Anker verwenden, $. Wir achten auch darauf, dass die Namen mit einem Begrenzungszeichen versehen sind \b. Dies schlägt für Dateien fehl, die Begrenzungszeichen wie $bar.coder enthalten %bar.c.


1
Dies beantwortet meine Frage nicht (Suche nach foo in allen Dateien mit dem Namen "bar * .c")
compie

1
@compie - in dem Sinne, dass ich Ihnen zeige, wie Sie einen Teil der gewünschten Dateien erhalten. Nach cppDateien suchen ack --type=cpp <string>. Weitere ackInformationen hierzu finden Sie in der Manpage von. Aber ich sage Ihnen im Grunde, dass Sie nicht so suchen können, ackwie Sie es möchten.
SLM

1
es antwortet also in dem Sinne, dass es zeigt, dass es acknicht tun kann, was gefragt wurde.
Xealits

@xealits - dieser Teil beantwortet es: Suche nach foo in bar * .c find adir -iname "bar*.c" | ack --files-from=- foo . Oder, wenn Sie nur eine Datei möchten:echo "barBaz.c" | ack --files-from=- foo
Alexanderbird

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

14

Es ist einfach, wenn der Dateityp bekannt ist und ack viele Dateitypen kennt. Wenn Sie beispielsweise nur in C-Dateien suchen möchten, können Sie Folgendes tun:

ack --cc 'string'

Wenn es sich jedoch nicht um eine der bekannten Erweiterungen handelt, müssen Sie Ihren eigenen Typ definieren. Das sollte funktionieren:

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

Beachten Sie, dass Sie sowohl --type-set als auch --barc benötigen.

(Danke an Andy, der auch auf der Mailingliste mitgeholfen hat.)


1
Ok, das funktioniert, aber die Verwendung von find und 'ack -x' ist einfacher. Ich denke, ich werde dabei bleiben.
Compie

Das Hinzufügen eines Links zu den Dokumenten hier wäre hilfreich. man ackhilft nicht wirklich und hat nicht, ccwenn ich das suche.
YPCrumble

ack --help = types Da fällt mir alles ein. Ich benutze es hauptsächlich für Python und Ada.
David Boshton

6

"Was ist neu in ack 2?" http://beyondgrep.com/ack-2.0/

Mit ack 2.0 können Sie das neue -x verwenden, um Dateinamen von einem Aufruf von ack in einen anderen zu leiten.

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

Nur ich kann es nicht zum Laufen bringen:

% 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.

So scheint es, dass -g einen regulären Ausdruck benötigt, während ich eine 'glob'-Stiloption möchte ...


2
Ja, -gbraucht einen regulären Ausdruck, keinen Glob. Du könntest deinen regulären Ausdruck schreiben als .*bar.*\.c$.
Andy Lester

2
@AndyLester Danke für die Bestätigung. Gefällt dir die Idee einer "Glob" -Option für ack?
Compie

3

Dies scheint am schnellsten und sichersten zu sein:

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

-x Liest die Liste der zu durchsuchenden Dateien in STDIN.

Wenn sich die Datei jedoch wahrscheinlich in Ihrer locateDatenbank befindet, ist dies noch schneller:

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

Locate akzeptiert auch reguläre Ausdrücke der alten Schule, die etwas schmerzhaft sind. Wenn Sie jedoch nach cDateien suchen , ist dies möglicherweise erforderlich. z.B

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

Das bedeutet einfach: "Alle Dateinamen durchsuchen, die mit c, cpp, h, hpp oder cc enden."


2

Ack unterstützt keine globale Dateiauswahl. Da ich das wirklich vermisse, habe ich ein kleines Shell-Skript ackg erstellt :

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

Jetzt können Sie den Befehl verwenden:

ackg foo "bar*.c"

Aber Achtung: Dies wird leider auch in Versionskontrollverzeichnissen (zB .git) gesucht.


2

Dies kann mit der -GOption ag geschehen , dem Silver Searcher (einem erweiterten Klon von ack-grep).

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

Anmerkungen:

  • agverwendet die PCRE- Syntax für reguläre Ausdrücke, daher muss bar.*\.cstattdessen der reguläre Ausdruck verwendet werden bar*.c.
  • Die -GOption muss vor dem Suchbegriff stehen, da alles, was danach folgt, als Dateiname interpretiert wird.

1

Möchten Sie nur ein bestimmtes Muster oder nur C-Quelldateien?

Wenn Sie alle C-Dateien möchten, verwenden Sie

ack --cc foo

Wenn Sie alle C-Dateien und NICHT C-Header-Dateien verwenden möchten

ack --cc --no-hh foo

1

Die Antwort von @chim ist die beste, aber sie wurde als Kommentar geschrieben. Ich poste sie also als formelle Antwort ...

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

Ich mag die Tatsache, dass Sie den Weg regexen können ...


Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.