Come posso ricorsivamente copiare i file per estensione, preservando la struttura delle directory?


71

Alla riga di comando di Linux, vorrei copiare un set (molto grande) di .txtfile da una directory (e le sue sottodirectory) a un'altra.

Ho bisogno che la struttura delle directory rimanga intatta e devo ignorare i file tranne quelli che finiscono .txt.


2
Avere cp e trovare come tag nella tua domanda, significa che sei legato a queste opzioni? Poiché il tuo set di dati è molto grande, ha senso presumere che il processo di copia possa essere interrotto per alcuni motivi e dovrai riavviarlo. Non sono sicuro che l'approccio find / cp sarà in grado di riprendere il trasferimento e copiare solo la parte mancante. Se non sei legato a find / cp, potresti considerare rsync, che è più intelligente. La sua opzione --exclude ti consentirà di saltare i file .txt.
vtest

Chiamata corretta - rsync è probabilmente l'opzione migliore. Non legato a find / cp. (Li ho usati comunque - rsync non era installato sul computer remoto, era un web server live e volevo lasciare il più piccolo spazio possibile)
bagaglio non reclamato il

Risposte:


96

Puoi usare find e cpio per farlo

cd /top/level/to/copy
find . -name '*.txt' | cpio -pdm /path/to/destdir

(-updm for overwrite destination content.)

perchè m? ho pensato che fosse solo per mantenere la data di modifica del file.
Mubashar,

7
cd /source/path
find -type f -name \*.txt -exec install -D {} /dest/path/{} \;

Ti stai perdendo un .dopo find. Anche su macOS 10.13.1, ha funzionato:find . -type f -name "*.txt" -exec install -v {} /dest/path/{} \;
triste

2

Un altro approccio

find . -name '*.txt' -exec rsync -R {} path/to/dext \;


Mi piace questa soluzione. Ero solito find . -iname '*.txt' -exec rsync -Rptgon {} path/to/dext \;fare una corrispondenza senza distinzione tra maiuscole e minuscole e la proprietà e le autorizzazioni di conservazione.
MountainX

1

Il modo più semplice che ha funzionato per me:

cp --parents -R jobs/**/*.xml ./backup/

un problema è che devi navigare nella directory "desiderata" prima che il "percorso principale" sia corretto.

Assicurati anche di aver abilitato globi ricorsivi in ​​bash:

shopt -s globstar

1

che ne dici di copiarlo con

cp -r /old/folder /new/folder

quindi vai alla nuova cartella ed esegui

find . -type f ! -iname "*.txt" -delete

o solo

cp -r /old/folder /new/folder && find . -type f ! -iname "*.txt" -delete

Modifica: ok vuoi un comando che filtri (non l'ho provato perché il mio sistema non ha il cpiocomando!). Qui è dove l'ho trovato: http://www.gnu.org/software/findutils/manual/html_mono/find.html#Copying-A-Subset-of-Files

find . -name "*.txt" -print0 |
     cpio -pmd0 /dest-dir

Per favore prova prima questo, perché non l'ho ancora provato. Se qualcuno verificasse, sarebbe fantastico.


annuisce Saluti: questo funzionerebbe, ma senza filtrare su .txt sto guardando alcuni milioni di file (che escono a poche centinaia di GB). Se necessario, forse dovrei, ma mi piacerebbe filtrare durante la copia, se possibile
bagaglio non reclamato,

1
Cheers, versione modificata funziona se mi tolgo la '0' dal -pmd0
unclaimedbaggage

Dovresti mantenere 0in -pmd0e aggiungere -print0alla fine del findcomando (poco prima di |).
G-Man,

1

Stavo cercando di fare la stessa cosa su macOS, ma nessuna delle opzioni ha funzionato davvero per me. Fino a quando l'ho scoperto ditto.

Ho dovuto copiare molti file .wav e farlo saltare i file video ... Quindi ecco cosa mi è venuto in mente:

find . -type f -iname "*.wav" -ls -exec ditto {} /destination/folder/{} \;

  • find .- Esegue trova nella cartella corrente. assicurati di cd /source/folderprima di iniziare

  • -type f - Specifica di cercare solo i file

  • -iname "*.wav" - Questo dice di cercare maiuscole / minuscole * .wav
  • -ls- Questo ti mostra il file su cui sta lavorando. Altrimenti non mostra nulla.
  • -exec ditto {} /destination/folder/{} \; - Fa tutto il lavoro di copia e creazione dei file con lo stesso albero di directory.

0

Vai alla directory:

find . -regex '<regexp_to_get_directories_and_files_you_want>' | xargs -i cp -r --parents {} path/to/destination

È un po 'più semplice e potente se gestisci le espressioni regolari.


-1

Vai alla directory:

cp '*.css' /path/to/destination

Dovrai accedere a ciascuna cartella della directory, ma questo è meglio della maggior parte delle opzioni che ho visto finora.


Questo metodo non è ricorsivo, nel senso che per le grandi directory potresti farlo per un bel po '...
Iain Reid,
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.