Ich habe das oft benutzt. Die Verbesserung, die ich erreichen möchte, besteht darin, Echo-Dateinamen zu vermeiden, die in grep nicht übereinstimmen. Besser dazu?
for file in `find . -name "*.py"`; do echo $file; grep something $file; done
Ich habe das oft benutzt. Die Verbesserung, die ich erreichen möchte, besteht darin, Echo-Dateinamen zu vermeiden, die in grep nicht übereinstimmen. Besser dazu?
for file in `find . -name "*.py"`; do echo $file; grep something $file; done
Antworten:
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/null
den Fall hinzu, dass es nur eine übereinstimmende Datei gibt, da grep
der Dateiname nicht gedruckt wird, wenn nur eine Datei zum Einsehen übergeben wird. Die GNU-Implementierung von grep
hat eine -H
Option 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 grep
zweimal für jede Datei auf - obwohl dies weniger effizient wäre, da mindestens ein grep
Befehl 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 find
so 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).
Wenn Sie GNU grep verwenden, können Sie die Option -r
oder 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, find
wenn Sie erweiterte Prädikate benötigen.
grep
, grep
aussehen 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.
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
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
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
. ag
wird 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.