In che modo copiare e rinominare i file trovati in "find" funzionano Linux?


17

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.


rinominarli, come? Se si sostituisce il delimitatore di directory con qualcosa - diciamo sottolineato (_), è possibile che si verifichino collisioni con file che contengono già una sottolineatura. Questo è vero per ogni personaggio valido, e accanto a / e \ 0, che sono vietati nei nomi dei file, non esiste un porto sicuro - qualsiasi personaggio potrebbe provocare una collisione.
utente sconosciuto

Le cartelle hanno sottocartelle o solo una struttura di cartelle ampia e semplice?
utente sconosciuto

Risposte:


8

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 = new_folder? Qual è lo scopo della barra rovesciata di fronte alla barra new_file/\/thumb?
utente sconosciuto

1
@utente: ${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.
Gilles 'SO- smetti di essere malvagio' il

Certo, ora lo vedo. :)
utente sconosciuto

1
Stai assumendo che le 487 directory siano direttamente sotto /home/user/temps, il che non è chiaro dalla domanda. Se non lo sono, devi trovare o **.
Gilles 'SO- smetti di essere malvagio' il

@Gilles - Lo sono davvero, è così che ho letto la domanda. Apprezzo il punto, però :)
simon

5

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.


Errore nei file che contengono una nuova riga nel loro nome.
utente sconosciuto

Bene, ha funzionato molto bene. una cosa in più, ho alcuni file zip anche in alcune sottodirectory. da lì è possibile estrarre anche le ime. ricorda 'zip not tar'
Mirage,

1

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.


0

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.


Ho alcuni file png in altre sottocartelle, funzionerà
Mirage,

per la mia cartella "A A", produce: mv -i ./A A/thumb.png ../tmp/.png- tutti i file finiscono in ../tmp/.png (../tmp è la mia directory di destinazione).
utente sconosciuto

Aggiungi virgolette e parentesi graffe intorno a tutte le variabili nel codice sopra, ad esempio "$ {dir}"
shellter

@ Mirror51 ha scritto: "i file in alcune sottocartelle funzioneranno". Sì dovrebbe. Sapevi che puoi eseguire ogni passaggio di questo script separatamente (o quando convogliati insieme, ogni set di pipe). È possibile eseguire solo il 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.
shellter

Non funzionerà read diresegue la suddivisione delle parole e prende, da una directory a\nbaeb come due istanze, che nessun mascheramento può risolvere.
utente sconosciuto

-1

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

Questa è solo una piccola parte della domanda del poster. Spiega ora come scorrere le directory e copiare le anteprime :-)

l'OP vuole usarefind

Sì, hai ragione ... Non so cosa mi sia successo ...
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.