Grep word in einer Datei und kopiere die Datei

9

Ich habe eine Sammlung von Dateien (* .zip, * .txt, * .tar.gz, * .doc, ... usw.). Diese Dateien befinden sich in einem Pfad. Ich möchte alle Dateien (* .txt) finden und dann nur die Textdateien kopieren, die bestimmte Wörter enthalten (z. B. LINUX / UNIX).

Ich habe folgendes ausgeführt:

find . -name "*.txt" | grep 'LINUX/UNIX'

Dieser Befehl konnte alle Textdateien finden und "grep" filterte die resultierenden Textdateien, indem nur die Textdateien aufgelistet wurden, die 'LINUX / UNIX' enthalten.

Wie kann ich diese endgültigen Dateien (dh die Textdateien, die 'LINUX / UNIX' enthalten) in einen bestimmten Pfad Ihrer Wahl kopieren?

Ich habe versucht mich zu bewerben xargs

find . -name "*.txt" | grep 'LINUX/UNIX' | xargs cp <to a path>

Aber es hat nicht funktioniert


quelle
Ziemlich genau wie der Befehl
Grep

Antworten:

21

Versuchen:

grep -rl --null --include '*.txt' LINUX/UNIX . | xargs -0r cp -t /path/to/dest

Da dieser Befehl die NUL-Trennung verwendet, ist er für alle Dateinamen sicher, einschließlich solcher mit schwierigen Namen, die Leerzeichen, Tabulatoren oder sogar Zeilenumbrüche enthalten.

Das oben genannte erfordert GNU cp. Versuchen Sie unter MacOS / FreeBSD:

grep -rl --null --include '*.txt' LINUX/UNIX . | xargs -0 sh -c 'cp "$@" /path/to/dest' sh

Wie es funktioniert:

  1. grep Optionen und Argumente

    • -rWeist grep an, die Verzeichnisstruktur rekursiv zu durchsuchen. (Unter FreeBSD -rfolgen Symlinks in Verzeichnisse. Dies gilt weder für OS / X noch für neuere Versionen von GNU grep.)

    • --include '*.txt'Weist grep an, nur Dateien zurückzugeben, deren Namen mit dem Glob übereinstimmen *.txt(einschließlich versteckter Dateien wie .foo.txtoder .txt).

    • -l Weist grep an, nur die Namen der übereinstimmenden Dateien zurückzugeben, nicht die Übereinstimmung selbst.

    • --nullWeist grep an, NUL-Zeichen zu verwenden, um die Dateinamen zu trennen. ( --nullWird unterstützt grepunter GNU / Linux , MacOS und FreeBSD aber nicht OpenBSD .)

    • LINUX/UNIX Weist grep an, nur nach Dateien zu suchen, deren Inhalt den regulären Ausdruck enthält LINUX/UNIX

    • .Suche im aktuellen Verzeichnis. Sie können es in neueren Versionen von GNU weglassen grep, müssen dann aber einen --Optionsabschluss übergeben cp, um sich vor Dateinamen zu schützen, die mit beginnen -.

  2. xargs Optionen und Argumente

    • -0 Weist xargs an, NUL-getrennte Eingaben zu erwarten.

    • -rweist xargs an, den Befehl nur auszuführen, wenn mindestens eine Datei gefunden wurde. (Diese Option wird weder unter BSD noch unter OSX benötigt und ist nicht mit OSX kompatibel xargs.)

    • cp -t /path/to/destkopiert die Verzeichnisse in das Zielverzeichnis. ( -terfordert GNU cp.)

John1024
quelle
Für Mac OS X und wahrscheinlich BSD möchten Sie --null anstelle von -Z verwenden. Ich denke auch, dass cp -tes nur Linux gibt.
Edward Falk
1
@ EdwardFalk Guter Punkt. Vielen Dank. Ich habe die --nullVersion aktualisiert und eine Version für BSD / OSX hinzugefügt, die nicht verwendet wird cp -t.
John1024
@ StéphaneChazelas Vielen Dank für die Verbesserungen.
John1024
1
OpenBSD grephat nicht --null.
Kusalananda
@Kusalananda Danke. Antwort aktualisiert, um festzustellen, dass OpenBSD nicht unterstützt --null.
John1024
14

Portabler (nur POSIX-Funktionen):

find . -type f -name '*.txt' -exec grep -q LINUX/UNIX {} \; -exec cp {} /path/to/dest \;
Platzhalter
quelle
3

Der folgende sh / Bash One Liner ist eine andere Methode, funktioniert jedoch nur im aktuellen Verzeichnis und wird nicht wiederholt:

for f in ./*.txt; do if grep -l 'LINUX/UNIX' "$f"; then cp "$f" /path/to/dest/; fi; done

Mit der -lOption grep wird eine Liste der Dateien gedruckt, die kopiert werden. Sie können sie jedoch verwenden, -qwenn Sie nichts auf dem Bildschirm sehen möchten.

Arronisch
quelle
0

Ich bin nicht sicher, warum die ursprüngliche Zeichenfolge nicht funktioniert hat. Der folgende Befehl funktioniert bei mir.

find / -name (Dateiname *) | grep '(filename.extention)' | xargs cp -t ./

In meinem Fall ist Dateiname * eine Sammlung von Dateien mit demselben Namen und unterschiedlichen Dateitypen (txt, zip usw.). Ich grep grep, um nur filename.txt herauszufinden und kopiere es in mein Zielverzeichnis (das derzeit ./ ist).

SamL
quelle