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.