Sposta ricorsivamente i file nelle sottodirectory in nuove sottodirectory con lo stesso nome


2

Ho una serie di file che terminano tutti con la stessa stringa, vale a dire: *_ext.datsituati in più sotto-directory insieme a molti altri file, in una determinata directory principale. Questa è la struttura:

/main_dir/subdir1/file11_ext.dat
/main_dir/subdir1/file12_ext.dat
/main_dir/subdir1/file13_ext.dat
/main_dir/subdir1/file14_other.dat
/main_dir/subdir1/file15_other.dat

/main_dir/subdir2/file21_ext.dat
/main_dir/subdir2/file22_ext.dat
/main_dir/subdir2/file23_ext.dat
/main_dir/subdir2/file24_other.dat
/main_dir/subdir2/file25_other.dat

/main_dir/subdir3/file31_ext.dat
/main_dir/subdir3/file32_ext.dat
/main_dir/subdir3/file33_ext.dat
/main_dir/subdir3/file34_other.dat
/main_dir/subdir3/file35_other.dat

Devo spostare in modo ricorsivo solo i file che finiscono *_ext.datin una nuova directory principale new_dir, rispettando la struttura della directory secondaria in modo che i file finiscano in una struttura di directory equivalente come questa:

/new_dir/subdir1/file11_ext.dat
/new_dir/subdir1/file12_ext.dat
/new_dir/subdir1/file13_ext.dat

/new_dir/subdir2/file21_ext.dat
/new_dir/subdir2/file22_ext.dat
/new_dir/subdir2/file23_ext.dat

/new_dir/subdir3/file31_ext.dat
/new_dir/subdir3/file32_ext.dat
/new_dir/subdir3/file33_ext.dat

Per questo motivo il comando dovrebbe anche creare quelle sottodirectory con i loro nomi corrispondenti. Lo so con una linea come questa:

find . -name "*_ext.dat" -print0 | xargs -0 rm -rf

Posso eliminare tutti quei file, ma non so come modificarlo per fare ciò di cui ho bisogno (o se è anche possibile).


1
Probabilmente qualcosa del genere rsync --include=*_ext.dat /main_dir/ /new_dir/farà il trucco. Non l'ho provato però.
— Jaap Eldering,

Risposte:


1

Desidero in primo luogo creare le sottodirectory in new_dirda

cd main_dir
for i in *; do mkdir "../new_dir/$i"; done
cd ..

Quindi è possibile utilizzare bash's forcomando di nuovo insieme con l'espansione del modello di fare esattamente quello che vi serve in fretta:

for i in main_dir/*/*_ext.dat; do cp "$i" "new_dir${i##main_dir}"; done

usando il fatto che esistono le directory di destinazione. Infine, se non fosse garantito che ciascuno di essi verrà effettivamente utilizzato, è possibile eliminare quelli vuoti in seguito:

cd new_dir
rmdir --ignore-fail-on-non-empty *

Nel primo ciclo ti aspetti che nel main_dirci siano solo directory. Inoltre non stai citando due volte i percorsi in tutto il tuo codice, quindi non funzionerà con nomi di file contenenti spazi. Questo codice sarà molto più robusto: for i in */; do mkdir "../new_dir/$i"; done. --- L'ultimo pezzo di codice non rimuoverà le directory che contengono directory vuote. Per questo puoi usare find: Come rimuovere le directory vuote nidificate usando uno script Bash su Linux?
— pabouk,

@pabouk Certo che lo sarà. (Forse non hai notato il cdprecedente?) La pagina man di rmdirdice: "DESCRIZIONE ... Rimuovi la (e) DIRECTORY (s), se sono vuote." L'opzione --ignore-fail-on-non-emptyesclude dagli avvertimenti che le directory non vuote sono state escluse. Inoltre, l'ho provato sul mio sistema prima di pubblicare.
— The Vee,

Inoltre, la struttura della directory che i miei comandi si aspettano concorda perfettamente con il modo in cui l'OP l'ha introdotta, inclusi i suoi esempi espliciti. Naturalmente i comandi sarebbero diversi se la struttura fosse.
— The Vee,

Grazie, comunque, per il commento sugli spazi. Fisso.
— The Vee,

Prego. Hai esagerato con le doppie virgolette. L'ultimo comando non farà quello che vuoi. --- Primo ciclo: non è meglio aggiungere single in /modo che il codice sia più universale e funzioni in più casi d'uso? --- L' ultimo comando non funziona: mkdir a ; cd a ; mkdir -p a/b/c d/e/f g/h/i ; ls ; rmdir --ignore-fail-on-non-empty * ; ls--- output:a d g a d g
— pabouk
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.