Filtro Rsync: copia un solo motivo


128

Sto cercando di creare una directory che ospiterà tutti e solo i miei PDF compilati da LaTeX. Mi piace tenere ogni progetto in una cartella separata, il tutto ospitato in una grande cartella chiamata LaTeX. Quindi ho provato a correre:

rsync -avn *.pdf ~/LaTeX/ ~/Output/

che dovrebbe trovare tutti i pdf ~/LaTeX/e trasferirli nella cartella di output. Questo non funziona Mi dice che non è stata trovata alcuna corrispondenza per " *.pdf". Se lascio fuori questo filtro, il comando elenca tutti i file in tutte le cartelle del progetto in LaTeX. Quindi è un problema con il filtro * .pdf. Ho provato a sostituire ~/con il percorso completo della mia directory home, ma questo non ha avuto effetto.

Sto usando zsh. Ho provato a fare la stessa cosa in bash e anche con il filtro che elencava ogni singolo file in ogni sottodirectory ... Cosa sta succedendo qui?

Perché rsync non capisce il mio unico filtro pdf?


OK. Quindi aggiorna: No, ci sto provando

rsync -avn --include="*/" --include="*.pdf" LaTeX/ Output/

E questo mi dà l'intero elenco dei file. Immagino perché tutto corrisponde al primo modello ...


Sembra che tu abbia ragione ... Penso che la mia risposta (usando il **modello di zsh ) dovrebbe funzionare, comunque.
Marcel Stimberg,

Risposte:


248

TL, DR:

rsync -am --include='*.pdf' --include='*/' --exclude='*' ~/LaTeX/ ~/Output/

Rsync copia le fonti nella destinazione. Se si passa *.pdfcome origine, la shell lo espande nell'elenco dei file con l' .pdfestensione nella directory corrente. Non si verifica alcun attraversamento ricorsivo perché non è stata passata alcuna directory come sorgente.

Quindi è necessario eseguire rsync -a ~/LaTeX/ ~/Output/, ma con un filtro per dire a rsync di copiare .pdfsolo i file. Le regole di filtro di Rsync possono sembrare scoraggianti quando leggi il manuale, ma puoi costruire molti esempi con poche semplici regole.

  • Inclusioni ed esclusioni:

    • Esclusione di file per nome o per posizione è facile: --exclude=*~, --exclude=/some/relative/location(relativa all'argomento di origine, ad esempio, questo esclude ~/LaTeX/some/relative/location).
    • Se si desidera abbinare solo alcuni file o posizioni, includerli, includere tutte le directory che li portano (ad esempio con --include=*/), quindi escludere il resto con --exclude='*'. Questo è perché:
    • Se si esclude una directory, questo esclude tutto ciò che si trova sotto di essa. I file esclusi non verranno considerati affatto.
    • Se includi una directory, questo non include automaticamente il suo contenuto. Nelle versioni recenti, --include='directory/***'lo farà.
    • Per ogni file, si applica la prima regola di corrispondenza (e viene incluso tutto ciò che non è mai stato trovato).
  • Patterns:

    • Se un modello non contiene un /, si applica alla directory sans del nome file.
    • Se uno schema termina con /, si applica solo alle directory.
    • Se un modello inizia con /, si applica all'intero percorso dalla directory a cui è stato passato come argomento rsync.
    • *qualsiasi sottostringa di un singolo componente della directory (cioè non corrisponde mai /); **corrisponde a qualsiasi sottostringa del percorso.
  • Se un argomento di origine termina con a /, i suoi contenuti vengono copiati ( rsync -r a/ bcrea b/fooper ogni a/foo). Altrimenti la directory stessa viene copiata ( rsync -r a bcrea b/a).


Quindi qui dobbiamo includere *.pdf, includere le directory che li contengono ed escludere tutto il resto.

rsync -a --include='*.pdf' --include='*/' --exclude='*' ~/LaTeX/ ~/Output/

Notare che questo copia tutte le directory, anche quelle che non contengono file o sottodirectory corrispondenti che ne contengano una. Questo può essere evitato con l' --prune-empty-dirsopzione (non è una soluzione universale poiché non è possibile copiare una directory anche abbinandola esplicitamente, ma è un requisito raro).

rsync -am --include='*.pdf' --include='*/' --exclude='*' ~/LaTeX/ ~/Output/

Contrariamente alla mia soluzione (usando il **modello di zsh ), questo ricrea la struttura della directory nella directory di destinazione. Non sono sicuro che questo sia ciò che l'OP vuole ...
Marcel Stimberg,

Voglio includere solo una directory ed escludere il resto di tutte le directory nel /etc/lsyncd/lsyncd.conf.luafile. Hai qualche idea?
Dhaduk Mitesh,

@DhadukMitesh Non ho familiarità con lsyncd. Dovresti porlo come una nuova domanda.
Gilles,

25
rsync -av --include="*/" --include="*.pdf" --exclude="*" ~/Latex/ ~/Output/ --dry-run

L'impostazione predefinita è includere tutto, quindi è necessario escludere esplicitamente tutto dopo aver incluso i file che si desidera trasferire. Rimuovere --dry-run per trasferire effettivamente i file.

Se inizi con:

--exclude '*' --include '*.pdf'

Quindi la corrispondenza avida escluderà tutto subito.

Se provi:

--include '*.pdf' --exclude '*' 

Quindi verranno trasferiti solo i file pdf nella cartella di livello superiore. Non seguirà alcuna directory, poiché quelle sono escluse da '*'.


2
A partire dal 17-03-2014 questa è la risposta migliore, poiché risolve esattamente la domanda dei manifesti originali . Per favore, votalo! Se aggiungi --prune-empty-dirs(o scorciatoia -m) ti risparmi anche molte directory vuote nella destinazione, tranne ovviamente che le desideri come promemoria o progetto strutturale.
porg

1
Migliore risposta, --include = "* /" è la chiave.
Martin Konicek,

Voglio includere solo una directory ed escludere il resto di tutte le directory nel /etc/lsyncd/lsyncd.conf.luafile. Hai qualche idea?
Dhaduk Mitesh,

15

Se si utilizza un modello simile *.pdf, la shell "espande" tale modello, ovvero sostituisce il modello con tutte le corrispondenze nella directory corrente. Il comando che stai eseguendo (in questo caso rsync) non è a conoscenza del fatto che hai provato a usare un modello.

Quando si utilizza zsh , esiste una soluzione semplice, tuttavia: il **modello può essere utilizzato per abbinare ricorsivamente le cartelle. Prova questo:

rsync -avn ~/LaTeX/**/*.pdf ~/Output/

Non copiare tutti i PDF da qualche parte all'interno della directory corrente e tutto da ~ / LaTeX / a ~ / Output?
SamB,

Immagino volessi dire rsync -avn ~/LaTeX/**/*.pdf ~/Output, ma la soluzione con --includeè comunque più scalabile.
Adam Byrtek,

Siamo spiacenti, ho corretto il comando che ho digitato male in fretta ... Sono d'accordo che il comando include (nella versione di SamB) è migliore, anche se è un po 'più complicato e specifico per rsync mentre **potrebbe essere utile anche in altre situazioni.
Marcel Stimberg,

1
Bash 4 ha adottato la stessa funzione. Oh, e non hai bisogno di rsync qui, cp lo farà. Su alcuni sistemi, se ci sono molti file, aiuta cd ~/Latex && cp -p **/*.pdf ~/Outputa evitare un errore di "riga di comando troppo lunga".
Gilles,

1
Nota che i pattern di rsync usati nei filtri include ed exclude hanno anche un ** che fa la stessa cosa. Puoi sfuggire a * da altre shell inserendole tra virgolette.
Dan Pritts,

13

È possibile utilizzare finde un elenco intermedio di file ( files_to_copy) per risolvere il problema. Assicurati di essere nella tua home directory, quindi:

find LaTeX/ -type f -a -iname "*.pdf" > files_to_copy && rsync -avn --files-from=files_to_copy ~/ ~/Output/ && rm files_to_copy

Testato con Bash.


Penso che find sia la soluzione più solida, ma opterei per l'utilizzo -execdell'opzione find o per l'utilizzo xargs. Qualcosa del tipo:find LaTeX/ -type f -iname "*.pdf" -print0 | xargs -0 -i rsync -avn {} Output/
Steven D,

Sì ... suggerirei di trovare anche ... anche se immagino che rsync debba essere in grado di farlo.
gabe.

Questa è una soluzione chiara anche a un problema più difficile: presumibilmente potrei usarlo per escludere file la cui classe di documenti è standaloneo che non hanno un .texfile con lo stesso nome, dal momento che saranno immagini incluse in alcuni documenti ...
Seamus,

2
L'opzione rsync --files-fromaccetta la lettura da stdin. Questo dovrebbe funzionare find LaTeX/ -type f -a -iname "*.pdf" | rsync -avn --files-from=- ~/ ~/Output/
Juan Calero

9

A giudicare dalla sezione "INCLUDI / ESCLUDI LE REGOLE DEL MODELLO" della manpage , il modo per farlo è

rsync -avn --include="*/" --include="*.pdf" ~/Latex/ ~/Output/

La differenza fondamentale tra questa e la risposta di kbrd è la --include="*/"bandiera, che dice a rsync di andare avanti e copiare tutte le directory che trova, qualunque esse siano chiamate. Ciò è necessario perché rsync non ricorre in una sottodirectory a meno che non sia stato incaricato di copiare quella sottodirectory.

Inoltre, notare che le virgolette impediscono alla shell di tentare di espandere i modelli in nomi di file relativi alla directory corrente e di effettuare una delle seguenti operazioni:

  1. Riuscire e incasinare il filtro (non troppo probabilmente nel mezzo di una bandiera del genere, anche se non si sa mai quando qualcuno creerà un file chiamato --include=foo.pdf...)

  2. Errore e potenziale produzione di un errore invece di eseguire il comando (come hai scoperto zsh fa per impostazione predefinita).


Quindi questo copierà solo i PDF e la struttura delle directory, mentre i kbrd copieranno i file, ma ignorerà la struttura?
Seamus,

1
Hmm. Questo in realtà sembra ancora provare a copiare tutto, immagino perché è quello che fa senza il filtro, quindi includel'ingestione di cose già presenti non cambia nulla. Se capisci cosa intendo ...
Seamus,

7
È necessario --exclude="*"dopo il --include="*.pdf", o questo trasferirà tutto.
jmanning2k,

@ jmanning2k: Ah. Buono a sapersi!
SamB,

4

Cosa ne pensi di questo:

rsync -avn --include="*.pdf" ~/Latex/ ~/Output/

No, man rsyncinserisce il filtro dopo le opzioni e prima della sorgente / delle destinazioni. Ci ho provato e non ha funzionato
Seamus,

A modo tuo, trova i file .pdf nella cartella corrente, ma non ricorsivamente, come voglio. (l' aopzione è per l'archivio e tra l'altro rende la copia ricorsiva.
Seamus

1
Ooops, mia cattiva. Ho aggiornato la mia risposta.
kbyrd,

+1 per essere così vicino e darmi un indizio su come trovare il materiale rilevante nella pagina del manuale. (Spero di aver capito bene. :-)
SamB,

3

Ecco qualcosa che dovrebbe funzionare senza usare find. La differenza rispetto alle risposte già pubblicate è l'ordine delle regole di filtro. Le regole di filtro in un comando rsync funzionano in modo molto simile alle regole di iptable, la prima regola che corrisponde a un file è quella utilizzata. Dalla pagina del manuale :

Man mano che viene creato l'elenco di file / directory da trasferire, rsync verifica a turno ogni nome da trasferire rispetto all'elenco dei modelli di inclusione / esclusione e viene applicato il primo modello di corrispondenza: se si tratta di un modello di esclusione, quel file è saltato; se si tratta di un modello di inclusione, quel nome file non viene ignorato; se non viene trovato alcun modello corrispondente, il nome file non viene ignorato.

Pertanto, è necessario un comando come segue:

rsync -avn --include="**.pdf" --exclude="*" ~/LaTeX/ ~/Output/

Nota il modello "**. Pdf". Secondo la pagina man :

se il modello contiene un / (senza contare un trailing /) o un "**", viene confrontato con il percorso completo, comprese le directory principali. Se il modello non contiene un / o un "**", viene confrontato solo con il componente finale del nome file. (Ricorda che l'algoritmo viene applicato in modo ricorsivo, quindi il "nome file completo" può effettivamente essere qualsiasi porzione di un percorso dalla directory iniziale in giù

Nel mio piccolo test, questo funziona in modo ricorsivo lungo l'albero delle directory e seleziona solo i pdf.


Come hai provato esattamente? Secondo la mia comprensione della documentazione e la mia verifica sperimentale, il tuo comando dovrebbe essere copiato solo *.pdfnella directory di livello superiore (ma non ~/LaTeX/foo/bar.pdf).
Gilles,

@Gilles Crud. Hai ragione. Ho giurato di averlo provato e ha funzionato, ma non riesco a ricrearlo. E ora che ho letto la pagina man che ho citato, ha senso che non funzioni. Brontolare.
Steven D,

1
Bene, ho capito dove il mio test era sbagliato. Il mio "piccolo test" era su una directory che aveva i miei file .tex e .pdf. Ho quindi creato una sottodirectory "test" e un test.pdf e test.tex in quella sottodirectory. Tuttavia, non ho notato che c'era un test.pdf nella mia directory di livello superiore, probabilmente a causa di un breve esperimento di LaTeX che ho fatto.
Steven D,

Non capisco ancora il **. Sarebbe bello avere un esempio. ;)
buhtz,

2

Questa è la mia soluzione preferita:

find source_dir -iname '*.jpg' -print0 |  rsync -0 -v --files-from=- . destination_dir/

Il findcomando è più semplice da comprendere rispetto alle regole di inclusione / esclusione di rsync:-)

Se vuoi copiare solo file pdf, basta cambiare .jpgin.pdf

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.