Ich möchte rekursiv nach dem Schlüsselwort "test" in allen Dateien suchen, die vom Typ "* .spec.in" im aktuellen Verzeichnis sind. Dies funktioniert nicht:
grep -rn "test" ./*.spec.in
Wie mache ich das?
Wenn Sie darüber nachdenken, was dies bewirkt, kann dies nicht funktionieren. Das -r-Flag bedeutet, dass grep ein Verzeichnis als Dateiquelle erwartet, Ihr Glob jedoch mit Dateien (oder gar nichts) übereinstimmt. Dies ist ein Missverhältnis.
Sie können dies auf verschiedene Arten tun.
Die "Lehrbuch" -Methode, die unter jedem UNIX (wirklich jeder Shell) verwendet werden kann, ist die Trennung der Verantwortung. Verwenden Sie find
diese Option, um die Rekursion durchzuführen, und führen Sie separat grep aus. Lass uns alle passenden Dateien finden und diese an grep übergeben
find . -type f -name '*.spec.in' | xargs grep -n "test"
Suchen Sie von hier aus nach Dateien, deren Name mit '* .spec.in' übereinstimmt, und übergeben Sie diesen Stream an xargs, wodurch der Stream in Befehlszeilenargumente für Ihr grep umgewandelt wird.
Wenn Sie keine Leerzeichen in Dateinamen haben, ist dies in Ordnung. Aber wenn Sie dies tun, oder wenn Sie dies verwenden, um Änderungen auf der Festplatte vorzunehmen, möchten Sie dies wahrscheinlich etwas strenger. Es gibt Hacks, bei denen Sie mit Dateinamen herumspielen können, um wichtige Dateien auf der Festplatte zu beschädigen. Sie sollten daher sehr vorsichtig mit Dateinamen-Hacks umgehen. Aus Sicherheitsgründen oder für Leerzeichen in Namen können Sie find und xargs anweisen, enger zu kommunizieren. Siehe -print0
, -0
unten.
find . -type f -name '*.spec.in' -print0 | xargs -0 something_destructive_like_rm
Auf neueren Shells wie zsh oder neueren Versionen von bash können Sie rekursive Globs verwenden, die eine spezielle ** Syntax verwenden. Sie stimmen rekursiv mit einem Dateimuster überein.
shopt -s globstar # needed for bash, not for zsh
grep "test" ./**/*.spec.in