Wie kopiere und benenne ich Dateien in "find" -Funktion von Linux?

17

Ich habe einen Ordner mit dem Namen /home/user/temps487 Ordner. In jedem Ordner habe ich eine Datei namens thumb.png.

Ich möchte alle Dateien mit dem Namen thumb.png in einen separaten Ordner kopieren und sie basierend auf dem Ordner, aus dem sie stammen, umbenennen.

Randhir Singh
quelle
benenne sie um, wie? Wenn Sie den Verzeichnisbegrenzer durch etwas ersetzen - sagen wir unterstrichen (_) -, können Kollisionen mit Dateien auftreten, die bereits eine Unterstreichung enthalten. Das gilt für jedes gültige Zeichen, und neben / und \ 0, die in Dateinamen verboten sind, gibt es keinen sicheren Hafen - jedes Zeichen kann eine Kollision hervorrufen.
Benutzer unbekannt
Haben Ordner Unterordner oder nur eine einfache, breite Ordnerstruktur?
Benutzer unbekannt

Antworten:

8

Bitte schön:

for file in /home/user/temps/*/thumb.png; do new_file=${file/temps/new_folder}; cp "$file" "${new_file/\/thumb/}"; done;

bearbeiten:

Die kanonische Weisheit ist übrigens, dass findes eine schlechte Idee ist, dies zu tun - die einfache Verwendung der Shell-Erweiterung ist viel zuverlässiger. Auch dies setzt voraus bash, aber ich denke, das ist eine sichere Annahme :)

2 bearbeiten:

Der Klarheit halber werde ich es aufschlüsseln:

# shell-expansion to loop specified files
for file in /home/user/temps/*/thumb.png; do

    # replace 'temps' with 'new_folder' in the path
    # '/home/temps/abc/thumb.png' becomes '/home/new_folder/abc/thumb.png'
    new_file=${file/temps/new_folder};

    # drop '/thumb' from the path
    # '/home/new_folder/abc/thumb.png' becomes '/home/new_folder/abc.png'
    cp "$file" "${new_file/\/thumb/}";
done;

Details zum ${var/Pattern/Replacement}Konstrukt finden Sie hier .

Die Anführungszeichen in der cpZeile sind wichtig, um Leerzeichen, Zeilenumbrüche usw. in Dateinamen zu behandeln.

simon
quelle
new_file = new_folder? Wozu dient der Backslash vor dem Slash-In new_file/\/thumb?
Benutzer unbekannt
1
@user: ${VARIABLE/PATTTERN/REPLACEMENT}Erzeugt den Wert von VARIABLE, wobei das Muster durch den Ersetzungstext ersetzt wird. Hier ist das Muster /thumb(das /muss maskiert werden, damit es nicht so aussieht ${new_file//PATTERN/REPLACEMENT}, was es zu einer globalen Ersetzung anstelle einer Ersetzung beim ersten Auftreten macht) und der Ersetzungstext ist leer.
Gilles 'SO- hör auf, böse zu sein'
Natürlich sehe ich es jetzt. :)
Benutzer unbekannt
1
Sie gehen davon aus, dass sich die 487-Verzeichnisse direkt darunter befinden /home/user/temps, was sich aus der Frage nicht ergibt. Wenn nicht, müssen Sie oder finden** .
Gilles 'SO- hör auf böse zu sein'
@ Gilles - ich bin in der Tat, so habe ich die Frage gelesen. Schätzen Sie den Punkt, obwohl :)
Simon
5

Dies funktioniert für beliebig tiefe Unterverzeichnisse:

$ find temps/ -name "thumb.png" | while IFS= read -r NAME; do cp -v "$NAME" "separate/${NAME//\//_}"; done
`temps/thumb.png' -> `separate/temps_thumb.png'
`temps/dir3/thumb.png' -> `separate/temps_dir3_thumb.png'
`temps/dir3/dir31/thumb.png' -> `separate/temps_dir3_dir31_thumb.png'
`temps/dir3/dir32/thumb.png' -> `separate/temps_dir3_dir32_thumb.png'
`temps/dir1/thumb.png' -> `separate/temps_dir1_thumb.png'
`temps/dir2/thumb.png' -> `separate/temps_dir2_thumb.png'
`temps/dir2/dir21/thumb.png' -> `separate/temps_dir2_dir21_thumb.png'

Der interessante Teil ist die Parametererweiterung ${NAME//\//_} . Es nimmt den Inhalt von NAMEund ersetzt jedes Vorkommen von /mit _.

Hinweis: Das Ergebnis ist abhängig vom Arbeitsverzeichnis und dem Pfadparameter für find. Ich habe den Befehl aus dem übergeordneten temporären Verzeichnis ausgeführt. Ersetzen Sie cpdurch, um echozu experimentieren.

Lesmana
quelle
Schlägt bei Dateien fehl, deren Name eine neue Zeile enthält.
Benutzer unbekannt
Nun, das hat sehr gut funktioniert. eine Sache mehr, ich habe einige zip-Dateien in einigen Unterverzeichnissen auch. Ist es möglich, auch von dort Imgae zu extrahieren? Denken Sie daran, 'zip not tar'
Randhir Singh
1

Kurzer Hilfecode:

#!/bin/bash
#
# echo cp "$1" ../tmp/"${1//\//_}" 
#
mv "$1" ../tmp/"${1//\//_}"

Nennen wir es 'deslash.sh' und machen es ausführbar. Nennen Sie es mit:

find -type f -name thumb.png -exec ./deslash.sh {} ";"    

Es wird fehlschlagen, wenn eine Kollision vorliegt

a/b/thumb.png # and 
a_b/thumb.png 

aber das ist unvermeidlich.

Benutzer unbekannt
quelle
0

Versuche dies

mkdir /home/user/thumbs
targDir=/home/user/thumbs

cd /home/user/temps

find . -type d | 
 while IFS="" read -r dir ; do
   if [[ -f "${dir}"/thumb.png ]] ; then
     echo mv -i "${dir}/thumb.png" "${targDir}/${dir}_thumb.png"
   fi
done

Bearbeiten

Ich habe Anführungszeichen hinzugefügt, falls in einem Ihrer Verzeichnisnamen Leerzeichen eingebettet sind.

Auch ich habe dies geändert, so dass nur die auszuführenden Befehle ausgedruckt werden. Untersuchen Sie die Ausgabe des Skripts, um sicherzustellen, dass alle Dateien / Pfadnamen korrekt aussehen. Wenn Sie sicher sind, dass es keine Probleme mit den auszuführenden Befehlen gibt, entfernen Sie die echo.

Shellter
quelle
Ich habe einige PNG-Dateien in einigen weiteren Unterordnern, wird das funktionieren
Randhir Singh
für meinen "A A" -Ordner erzeugt er: mv -i ./A A/thumb.png ../tmp/.png- Alle Dateien enden in ../tmp/.png (../tmp ist mein Zielverzeichnis).
Benutzer unbekannt
Fügen Sie alle Variablen im obigen Code in Anführungszeichen und geschweifte Klammern ein, z. B. "$ {dir}"
Shellter,
@ Mirror51 hat geschrieben: "Dateien in einigen weiteren Unterordnern, wird das funktionieren". Ja das sollte es. Wussten Sie, dass Sie jeden Schritt dieses Skripts separat ausführen können (oder, wenn die Pipes zusammengesetzt sind, jeden Satz von Pipes)? Sie können nur das ausführen find -type dund die Ausgabe sehen. Enthält das alle Verzeichnisse, die Sie erwarten? Sollte dies nicht der Fall sein, fügen Sie bitte eine Ausgabe hinzu, um das Problem anzuzeigen. Viel Glück.
Shellter
Wird nicht funktionieren. read dirführt die Wortteilung durch und nimmt aus einem Verzeichnis a\nba und b zwei Instanzen, die keine Maskierung lösen kann.
Benutzer unbekannt
-1

Zum Kopieren benötigen Sie den Befehl cp und zum Umbenennen unter Linux müssen Sie die Datei mit dem Befehl mv verschieben . Unter Linux müssen Sie immer den gesamten Pfad angeben, von der Quelle, wenn Sie sich in einem anderen Ordner befinden, und natürlich zum Zielordner. Ich würde so etwas für die Kopie sein:

cp /source_path/file /destination_path/

oder umbenennen oder verschieben

mv /source_path/old_file /destination_path/new_name_file

quelle
Dies ist nur ein kleiner Teil der Frage des Posters. Erklären Sie nun, wie Sie die Verzeichnisse
die OP will verwendenfind
Ja, du hast recht ... Ich weiß nicht, was mit mir passiert ist ...