3 Stimmen

Wie schreibe ich einen Bash-Alias/Funktion, um alle Dateien in allen Unterverzeichnissen nach einer Zeichenfolge zu durchsuchen?

Ich habe den folgenden Befehl verwendet, um nach einer Zeichenkette in allen Python-Quelldateien in und unter meinem aktuellen Verzeichnis zu suchen:

find . -name '*.py' -exec grep -nHr <string> {} \;

Ich würde die Dinge gerne vereinfachen, so dass ich einfach etwas eingeben kann wie

findpy <string>

Und erhalten genau das gleiche Ergebnis. Aliase scheinen nicht ausreichend, da sie nur eine Zeichenfolgenexpansion tun, und das Argument, das ich angeben muss, ist nicht das letzte Argument. Es klingt wie Funktionen sind für die Aufgabe geeignet, so habe ich mehrere Fragen:

  • Wie schreibe ich ihn?
  • Wo soll ich es hinstellen?

10voto

Gordon Davisson Punkte 105638

Wenn Sie nicht ein ganzes Skript dafür erstellen wollen, können Sie dies auch mit einer Shell-Funktion tun:

findpy() { find . -name '*.py' -exec grep -nHr "$1" {} \; ; }

...aber dann müssen Sie ihn möglicherweise sowohl in ~/.bashrc als auch in ~/.bash_profile definieren, damit er sowohl für Login- als auch für interaktive Shells definiert wird (siehe den Abschnitt INVOCATION in der Manpage der Bash).

0 Stimmen

Meine Distribution hat es so eingerichtet, dass die einzige Aktion, die .bash_profile ausführt, die Quelle von .bashrc ist, also ist es kein Problem. Danke!

1 Stimmen

Funktionen und Aliasse sollten in ~/.bashrc und ~/.bash_profile oder ~/.profile sollten ~/.bashrc als Quelle verwenden

0 Stimmen

Ja, das eine vom anderen zu beziehen, macht das Leben viel einfacher. Zur Sicherheit lasse ich mein .bash_profile zuerst überprüfen, etwa so: if [ -f ~/.bashrc ]; then . ~/.bashrc; fi

6voto

Idelic Punkte 13890

Alle obigen "find ... -exec"-Lösungen sind in dem Sinne in Ordnung, dass sie funktionieren, aber sie sind furchtbar ineffizient und werden bei großen Bäumen extrem langsam sein. Der Grund dafür ist, dass sie einen neuen Prozess für jede einzelne *.py-Datei. Verwenden Sie stattdessen xargs(1) und führen Sie grep nur auf Dateien (nicht auf Verzeichnisse) aus:

#! /bin/sh
find . -name \\\*.py -type f | xargs grep -nHr "$1"

Zum Beispiel:

$ time sh -c 'find . -name \\\*.cpp -type f -exec grep foo {} \\; >/dev/null'
real    0m3.747s
$ time sh -c 'find . -name \\\*.cpp -type f | xargs grep foo >/dev/null'
real    0m0.278s

0 Stimmen

Wie funktioniert time sh -c 'find . -name *.cpp -type f -exec grep foo {} + >/dev/null' im Vergleich? Für mich war es etwas schneller als xargs, aber xargs gab mir bei einigen Python-Dateien mit Leerzeichen im Namen (danke cmu) einige "no such file or directory errors". Die -exec-Versionen haben sich nicht beschwert.

0 Stimmen

Die Verwendung von "-exec ... +" sollte in Bezug auf die Leistung gleichwertig mit xargs sein, ist aber nicht portabel und nicht so flexibel wie xargs. Leerzeichen in Dateinamen können einfach behandelt werden, indem man -print0 an find und -0 an args übergibt, so dass Dateinamen durch NUL-Zeichen anstelle von Leerzeichen begrenzt werden, d.h. "find -name *.cpp -print0 | xargs -0 grep foo'.

0 Stimmen

Tatsächlich habe ich gerade überprüft, dass "-exec ... +" in POSIX enthalten ist und daher als portabel angesehen werden kann. Damit bleibt nur noch Flexibilität als Argument für xargs übrig :-)

6voto

Danny Punkte 11834

Nebenbei bemerkt, sollten Sie einen Blick auf Folgendes werfen Ack für das, was Sie tun. Es ist als Ersatz für das in Perl geschriebene Grep gedacht. Filtern von Dateien basierend auf der Zielsprache oder Ignorieren von .svn-Verzeichnissen und dergleichen.

Beispiel (Schnipsel aus dem Trac-Quelltext):

$ ack --python foo ./mysource
ticket/tests/wikisyntax.py
139:milestone:foo
144:<a class="missing milestone" href="http://stackoverflow.com/milestone/foo" rel="nofollow">milestone:foo</a>

ticket/tests/conversion.py
34:        ticket['foo'] = 'This is a custom field'

ticket/query.py
239:        count_sql = 'SELECT COUNT(*) FROM (' + sql + ') AS foo'

2voto

Shalom Craimer Punkte 19519

Ich wollte etwas Ähnliches, und die Antwort von Idelic erinnerte mich an eine der schönen Eigenschaften von xargs : dass der Befehl am Ende steht. Mein Problem war, dass ich einen Shell-Alias schreiben wollte, der "Parameter akzeptiert" (wirklich, dass er sich so erweitert, dass ich Parameter übergeben kann, also grep ).

Hier ist, was ich zu meinem bash_aliases :

alias findpy="find . -type f -name '*.py' | xargs grep"

Auf diese Weise könnte ich schreiben findpy WORD ou findpy -e REGEX ou findpy -il WORD - Der Punkt ist, dass man jede grep Befehlszeilenoption.

1voto

Chas. Owens Punkte 62716

Fügen Sie die folgenden drei Zeilen in eine Datei namens findpy

#!/bin/bash

find . -name '*.py' -exec grep -nHr $1 {} \;

Dann sagen Sie

chmod u+x findpy

Ich habe normalerweise ein Verzeichnis namens bin in meinem Home-Verzeichnis, wo ich kleine Shell-Skripte wie dieses ablege. Stellen Sie sicher, dass Sie das Verzeichnis zu Ihrem PATH .

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X