Ho una cartella chiamata /home/user/tempsche ha 487 cartelle. In ogni cartella ho un file chiamato thumb.png.
Voglio copiare tutti i file denominati thumb.png in una cartella separata e rinominarli in base alla cartella da cui provengono.
Ho una cartella chiamata /home/user/tempsche ha 487 cartelle. In ogni cartella ho un file chiamato thumb.png.
Voglio copiare tutti i file denominati thumb.png in una cartella separata e rinominarli in base alla cartella da cui provengono.
Risposte:
Ecco qui:
for file in /home/user/temps/*/thumb.png; do new_file=${file/temps/new_folder}; cp "$file" "${new_file/\/thumb/}"; done;
modificare:
la saggezza canonica, a proposito, è che usare findper questo è una cattiva idea - semplicemente usare l'espansione della shell è molto più affidabile. Inoltre, questo presuppone bash, ma immagino che sia un presupposto sicuro :)
modifica 2:
per chiarezza, lo analizzerò:
# 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;
i dettagli sul ${var/Pattern/Replacement}costrutto sono disponibili qui .
le virgolette nella cpriga sono importanti per gestire spazi, newline ecc. nei nomi dei file.
new_file/\/thumb?
${VARIABLE/PATTTERN/REPLACEMENT}produce il valore di VARIABLEma con il motivo sostituito dal testo sostitutivo. Qui il modello è /thumb( /deve essere evitato in modo che non sembri ${new_file//PATTERN/REPLACEMENT}, il che lo rende una sostituzione globale invece di una sostituzione di prima occorrenza) e il testo di sostituzione è vuoto.
/home/user/temps, il che non è chiaro dalla domanda. Se non lo sono, devi trovare o **.
Questo funziona per le sottodirectory arbitrariamente profonde:
$ 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'
La parte interessante è l' espansione dei parametri ${NAME//\//_} . Prende il contenuto di NAMEe sostituisce ogni ricorrenza di /con_ .
Nota: il risultato dipende dalla directory di lavoro e dal parametro path per find. Ho eseguito il comando dalla directory padre di temps. Sostituisci cpcon echoper sperimentare.
Codice di aiuto breve:
#!/bin/bash
#
# echo cp "$1" ../tmp/"${1//\//_}"
#
mv "$1" ../tmp/"${1//\//_}"
chiamiamolo "deslash.sh" e rendiamolo eseguibile. Chiamalo con:
find -type f -name thumb.png -exec ./deslash.sh {} ";"
Fallirà, se esiste una collisione
a/b/thumb.png # and
a_b/thumb.png
ma è inevitabile.
Prova questo
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
modificare
Ho aggiunto delle citazioni nel caso in cui uno dei nomi delle tue directory contenga caratteri di spazi bianchi incorporati in esse.
Inoltre ho modificato questo in modo che stamperà solo i comandi da eseguire. Esamina l'output dello script per assicurarti che tutti i nomi di file / percorsi siano corretti. Quando sei sicuro che non ci sono problemi con i comandi che verranno eseguiti, rimuovi il file echo.
mv -i ./A A/thumb.png ../tmp/.png- tutti i file finiscono in ../tmp/.png (../tmp è la mia directory di destinazione).
find -type de vedere l'output. Ti arrivano tutte le directory che ti aspetti? In caso contrario, aggiungere un output per mostrare il problema. In bocca al lupo.
read diresegue la suddivisione delle parole e prende, da una directory a\nbaeb come due istanze, che nessun mascheramento può risolvere.
Per copiare è necessario il comando cp , e rinominare per Linux è lo stesso che spostare il file, quindi è necessario farlo con il comando mv . In Linux devi sempre specificare l'intero percorso, dall'origine, se ti trovi in un'altra cartella, e alla cartella di destinazione, ovviamente. Sarei qualcosa del genere, per copia:
cp /source_path/file /destination_path/
o per rinominare o spostare
mv /source_path/old_file /destination_path/new_name_file