Ich habe einige solcher Dateien in einem Verzeichnis
00.01.02 0000 some filename 1.pdf
00.01.02 0000 some filename 1.txt
02.03.07 0163 another filename 2.pdf
02.03.07 0163 another filename 2.txt
und ich muss alle TXT-Dateien finden, die eine bestimmte Zeichenfolge enthalten, und dann diese TXT-Datei und die entsprechende PDF-Datei in ein anderes Verzeichnis verschieben.
Wie lässt sich dies am besten erledigen?
Antwort1
Ich habe 3 Optionen für Sie. Die Grundideen sind:
grep | xargs mv
grep | parallel mv
find -exec grep -q -exec mv
1.grep | xargs mv
Verwenden Sie grep
und xargs
:
grep -FlZ "some string" *.txt \
| xargs -0 -I{} sh -c 'echo mv "$1" "${1%.*}.pdf" some/other/directory' xargs-sh {}
grep
:
-F
Übereinstimmung mit einer vollständigen Zeichenfolge, nicht mit einem Muster-l
Ausgabe nur mit übereinstimmenden Dateinamen-Z
Null-Trennzeichen zwischen Dateinamen ausgeben (Das ist wichtig, weil Dateinamen Zeilenumbrüche enthalten dürfen, Sie sich also nicht auf einen Zeilenumbruch als Trennzeichen verlassen können)
xargs
:
-0
liest nullbegrenzte Daten
2.grep | parallel mv
Mit xargs
müssen Sie eine Subshell aufrufen, sh -c
um den entsprechenden PDF-Dateinamen abrufen zu können.
Stattdessen können Sie auch GNU parallel
coole Features nutzen!!
grep -FlZ "some string" *.txt \
| parallel -0 -j1 echo mv {} {.}.pdf some/other/directory
-j1
immer nur ein Auftrag gleichzeitig{}
der Dateiname{.}
Dateiname ohne Erweiterung
3.find -exec grep -q -exec mv
Und noch eine Alternative mit find
:
find . -maxdepth 1 -name "*.txt" \
-exec grep -Fq "some string" {} \; \
-exec sh -c 'echo mv "$1" "${1%.*}.pdf" some/other/location' find-sh {} \;
-maxdepth 1
nicht rekursivgrep -q
um nur den Fehlercode anstelle der Dateinamen zu erhalten,-exec
wird der zweite nur ausgeführt, wenn der erste erfolgreich war.- Die zweite Option
-exec
ist grundsätzlich die gleiche wie beixargs
der ersten. - wir müssen keine durch Nullen getrennte Ausgabe machen, weil wir keine Dateinamen übergeben,
find
das kümmert sich.
Entfernen Sie für jede Option das, echo
wenn Sie mit der Ausgabe zufrieden sind.
Antwort2
Zerlegen Sie das Problem in Einzelteile.
„Ich muss alle Textdateien im aktuellen Verzeichnis finden, die eine bestimmte Zeichenfolge enthalten.“
grep -F "text string just as written (no regex)" *.txt
"Ich will dasDateinamendieser Dateien"
grep -l -F "text string" *.txt
„Für jede dieser Dateien …“
for...each verwenden Sie ein while/do/done
Konstrukt, an das Sie die Dateiliste übergeben. Für jede Datei können Sieetwas, die Zugriff auf die Variable haben $file
:
grep -l -F "text string" *.txt \
| while IFS= read -r file ; do
...something...
done
Das „Etwas“ ist
„...verschieben Sie die txt-Datei und die entsprechende pdf-Datei...“
Sie benötigen also den Basisnamen ohne ".txt"
BASE=$( basename ${file} .txt )
Und zum Schluss alles zusammenfassen:
grep -l -F "text string" *.txt \
| while IFS= read -r file ; do \
BASE=$( basename ${file} .txt )
mv ${BASE}.txt /some/other/dir
mv ${BASE}.pdf /some/other/dir
done
(Beachten Sie, dass hiervon ausgegangen wird, dass jederDateiist ohne Pfad, weil basename
es sonst abgestreift würde).
Antwort3
Wenn Sie keinen parallel
Befehl haben, machen Sie mit zwei xargs
wie unten
grep -l 'search string' *.txt | xargs -I {} basename {} .txt | xargs -I {} cp {}.pdf /destination-directory