Wie verwende ich find, um alle gefundenen Dateien in einen neuen Namen in denselben Verzeichnissen zu kopieren?

8265
Michael Prescott

Ich habe einen einfachen Befehl, der fast das macht, was ich will. Im Folgenden werden alle Dateien mit dem Suffix '_compressed.swf' gesucht und in das gleiche Verzeichnis mit dem Zusatz '.bak2' kopiert:

find '../content' -name '* _compressed.swf' -print0 | xargs -0 -I {} cp {} {} .bak2

Ergebnisse
in: /content/somefile_compressed.swf
Out: /content/somefile_compressed.swf.bak2

Ich muss jedoch '_compressed.swf' durch '_content.swf' ersetzen, das ich find verwenden möchte, anstatt rekursives Flag auf cp zu verwenden.

Ziel
In: /content/somefile_compressed.swf
Out: /content/somefile_content.swf

4
Cross-posted hier: http://serverfault.com/questions/115880/how-do-i-use-find-to-copy-all-found-files-to-a-new-name-in-their-same -Verzeichnisse Dennis Williamson vor 14 Jahren 1

3 Antworten auf die Frage

4
John T

Diese Lösung ist wahrscheinlich die tragbarste:

find "../content" -name "* _compressed.swf" -exec sh -c 'cp {} `dirname {}` / `basename {} compress.swf`content.swf' \; 

Es gibt auch den berühmten rename.pl Skript, das mit Perl und das verteilt wird Umbenennungs Befehl, der diese etwas einfacher gemacht haben könnte. Diese sind jedoch nicht auf allen Distributionen verfügbar. Diese Befehle sind größtenteils vorhanden.

Das Obige verschiebt die Dateien von ihrem aktuellen Speicherort an den Speicherort des Skripts und fügt das Suffix 'content.swf' hinzu. Das Ersetzen von mv durch cp bringt mich näher, aber ich muss immer noch Text im Namen anstelle von Anhängen ersetzen. Ich komme mit sed näher, lerne aber trotzdem. Michael Prescott vor 14 Jahren 0
@Michael du hast recht! Hoppla. Ich habe nur im aktuellen Verzeichnis getestet, weshalb es für mich funktioniert hat. Ich habe es behoben :) John T vor 14 Jahren 0
Hey, danke John. Ich mag das. Vieles davon ist für mich alles neu. Ich verstehe die Verwendung von find, -exec, sh, dirname {}, basename {}, aber ich bin etwas verwirrt über die kombinierte Verwendung. sh -c '' konvertiert den String in einen Befehl und führt den Befehl aus, oder? mv {} erweitert sich zu einem der Suchergebnisse "mv ../content/file1of20_compressed.swf ???????" Es ist der zweite Teil dessen, was ich noch nicht verstehe. Was bewirkt, dass die komprimierte.swf durch content.swf ersetzt wird? In meiner Lösung können Sie sehen, wie ich gerade gelernt habe, wie man sed benutzt. Michael Prescott vor 14 Jahren 0
@Michael Was passiert, ist, dass die Datei mit einem neuen Namen verschoben wird. Wenn `{}` `/ etc / somefile_compressed.swf` enthielt, benötigt dirname` / etc` und `basename {} compress.swf` Sie mit` somefile_`. Jetzt setzen Sie diese 2 zusammen mit dem Schrägstrich, den ich in der Mitte (`/`) hinzugefügt habe, und Sie haben `/ etc / somefile_`. Sie werden feststellen, dass ich am Ende `content.swf` hinzugefügt habe, sodass die Anweisung als` / etc / somefile_content.swf` abgeschlossen wird. HTH. John T vor 14 Jahren 2
Ich würde * rename.pl * verwenden, wenn * mv * -Funktionalität gewünscht wurde (es ist nicht schwierig, mit Perl ein System hinzuzufügen), aber die * cp * -Datei macht dies zu einem anderen Biest. Sie müssten das Skript anpassen, um eine Kopie zu erstellen, anstatt umzubenennen, was funktionieren würde, aber es ist mehr Arbeit. @John - nette * find * lösung; Es ist groß und lang und hässlich, aber es sieht so aus, als würde es funktionieren. (Bitte nicht, mir zu helfen, es zu testen!) :) quack quixote vor 14 Jahren 0
@ ~ quack Ich habe den CP-Teil total verpasst! behoben, danke :) John T vor 14 Jahren 0
1
Michael Prescott

Ich bin sicher, dass dies alles in einer Zeile gehandhabt werden kann. Ich kam einer einzeiligen Lösung sehr nahe und mit etwas Hilfe noch näher, aber ohne Erfolg. Die folgenden Arbeiten:

#!/bin/bash  # Read all file names into an array FilesArray=($(find "../content" -name "*_compressed.swf"))  # Get length of an array FilesIndex=${#FilesArray[@]}   # Use for loop read all directory names for (( i=0; i<$; i++ )); do source="$" destination="$(echo "$" | sed 's/compressed/content/')" cp "$" "$" done  exit 0; 
0
jonathanserafini

Ich glaube, das sollte den Trick tun und ist zu einem One-Liner zusammenlegbar, wenn man es wirklich braucht;)

find ../content -name '*_compressed.swf' | while read file do cp "$file" "$" done 

Die Bash-Pattern-Substitution funktioniert in diesen Fällen gut.