Ho una cartella chiamata /home/user/temps
che 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/temps
che 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 find
per 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 cp
riga sono importanti per gestire spazi, newline ecc. nei nomi dei file.
new_file/\/thumb
?
${VARIABLE/PATTTERN/REPLACEMENT}
produce il valore di VARIABLE
ma 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 NAME
e 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 cp
con echo
per 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 d
e 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 dir
esegue la suddivisione delle parole e prende, da una directory a\nb
aeb 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