Dateinamen nur mit gefundenem Muster suchen und ausgeben

Antworten:

23
find . -name '*.py' -exec grep something {} \; -print

würde den Dateinamen nach den übereinstimmenden Zeilen ausgeben.

find . -name '*.py' -exec grep something /dev/null {} +

würde den Dateinamen vor jeder übereinstimmenden Zeile ausgeben (wir fügen /dev/nullden Fall hinzu, dass es nur eine übereinstimmende Datei gibt, da grepder Dateiname nicht gedruckt wird, wenn nur eine Datei zum Einsehen übergeben wird. Die GNU-Implementierung von grephat eine -HOption dafür als Alternative).

find . -name '*.py' -exec grep -l something {} +

würde nur die Dateinamen der Dateien drucken, die mindestens eine übereinstimmende Zeile haben.

Um den Dateinamen vor den übereinstimmenden Zeilen auszudrucken , können Sie stattdessen awk verwenden:

find . -name '*.py' -exec awk '
  FNR == 1 {filename_printed = 0}
  /something/ {
    if (!filename_printed) {
      print FILENAME
      filename_printed = 1
    }
    print
  }' {} +

Oder rufen Sie grepzweimal für jede Datei auf - obwohl dies weniger effizient wäre, da mindestens ein grepBefehl und bis zu zwei für jede Datei ausgeführt würden (und lesen Sie den Inhalt der Datei zweimal):

find . -name '*.py' -exec grep -l something {} \; \
                    -exec grep something {} \;

In jedem Fall möchten Sie nicht die Ausgabe von findso durchlaufen und denken Sie daran, Ihre Variablen in Anführungszeichen zu setzen .

Wenn Sie eine Shell-Schleife mit GNU-Werkzeugen verwenden wollten:

find . -name '*.py' -exec grep -l --null something {} + |
   xargs -r0 sh -c '
     for file do
       printf "%s\n" "$file"
       grep something < "$file"
     done' sh

(Funktioniert auch mit FreeBSD und Derivaten).

Stéphane Chazelas
quelle
6

Wenn Sie GNU grep verwenden, können Sie die Option -roder verwenden --recursive, um diese einfache Suche für Sie durchzuführen:

grep -r --include '*.py' -le "$regexp" ./ # for filenames only
grep -r --include '*.py' -He "$regexp" ./ # for filenames on each match

Sie benötigen nur, findwenn Sie erweiterte Prädikate benötigen.

Toby Speight
quelle
1
Je nach Version der GNU grep, grepaussehen kann oder nicht innerhalb Symlinks oder Traverse symbolische Links zu Verzeichnissen. Möglicherweise gibt es auch Unterschiede in der Behandlung anderer Arten von nicht regulären Dateien.
Stéphane Chazelas
5

Sie können grep anweisen, den Dateinamen in die Ausgabe aufzunehmen. Wenn es also eine Übereinstimmung gibt, wird diese auf der Konsole angezeigt. Wenn in einer Datei keine Übereinstimmung vorliegt, wird für diese Datei keine Zeile gedruckt.

find . -name "*.py" | xargs grep -n -H something

Aus dem man grep:

-H       Always print filename headers with output lines
-n, --line-number
         Each output line is preceded by its relative line number in the file, starting at line 1.  The line number counter is reset for each file processed.
         This option is ignored if -c, -L, -l, or -q is specified.

Wenn Ihre Dateien Namen mit Leerzeichen enthalten, müssen Sie die Pipe umschalten, um NUL-Zeichen als Trennzeichen zu verwenden. Der vollständige Befehl sieht nun folgendermaßen aus:

find . -name "*.py" -print0 | xargs -0 grep -n -H something
rollstuhlfahrer
quelle
1

Sie können versuchen, etwas wie:

find . -name "*.py:" -exec grep -l {} \;

Dieser Befehl exec grep für jede Datei, die mit dem Befehl find und seiner Standardfunktion find ermittelt wurde

Romeo Ninov
quelle
1

Verwenden Sie das -lArgument.

for file in `find . -name "*.py"`; do grep -l something $file && grep something $file; done

Eine sinnvollere Verwendung wäre:

for file in $(find . -name '*.py' -exec grep -l something '{}' +); do echo "$file"; grep something $file; done
kmkaplan
quelle
1

Es gibt grep Alternativen, deren Ergebnisse standardmäßig im gewünschten Format ausgegeben werden. Die 2 beliebtesten, die ich kenne, sind ag(aka "der silberne Sucher") und ack. agwird als schnellere Alternative zu beworben ack.

$ ag '^\w+\s*\w+\(' ~/build/i3/src
build/i3/src/display_version.c
58:void display_running_version(void) {

build/i3/src/load_layout.c
42:static TAILQ_HEAD(focus_mappings_head, focus_mapping) focus_mappings =
518:json_content_t json_determine_content(const char *filename) {
575:void tree_append_json(Con *con, const char *filename, char **errormsg) {

build/i3/src/x.c
64:CIRCLEQ_HEAD(state_head, con_state) state_head =
67:CIRCLEQ_HEAD(old_state_head, con_state) old_state_head =
70:TAILQ_HEAD(initial_mapping_head, con_state) initial_mapping_head =
97:void x_con_init(Con *con, uint16_t depth) {
...

Ich kann es Ihnen hier nicht zeigen, aber die Ausgabe ist ordentlich gefärbt. Ich bekomme die Dateinamen in Olivgrün, die Zeilennummern in Goldgelb und das passende Teil in jeder Zeile in Blutrot. Die Farben sind jedoch anpassbar.

JoL
quelle