it-swarm.it

Filtro Rsync: copia un solo motivo

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 in ~/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 ciò non ha avuto alcun effetto.

Sto usando zsh. Ho provato a fare la stessa cosa in bash e persino 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 ...

142
Seamus

TL, DR:

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

Rsync copia le fonti nella destinazione. Se passi *.pdf come origini, Shell lo espande all'elenco dei file con .pdf extension nella directory corrente. Non si verifica alcun attraversamento ricorsivo perché non è stata passata alcuna directory come sorgente.

Quindi devi eseguire rsync -a ~/LaTeX/ ~/Output/, ma con un filtro per dire a rsync di copiare .pdf solo 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:

    • Escludere i file per nome o per posizione è facile: --exclude=*~, --exclude=/some/relative/location (relativo all'argomento source, ad esempio questo esclude ~/LaTeX/some/relative/location).
    • Se desideri abbinare solo alcuni file o posizioni, includili, includi ogni directory che li porta (ad esempio con --include=*/), quindi escludi il resto con --exclude='*'. Questo è perché:
    • Se si esclude una directory, ciò esclude tutto ciò che si trova al di 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 corrispondente (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 che è stata passata come argomento a rsync.
    • * qualsiasi sottostringa di un singolo componente di directory (ovvero non corrisponde mai a /); ** corrisponde a qualsiasi sottostringa del percorso.
  • Se un argomento di origine termina con un /, i suoi contenuti vengono copiati (rsync -r a/ b crea b/foo per ogni a/foo). Altrimenti viene copiata la directory stessa (rsync -r a b crea b/a).


Quindi qui dobbiamo includere *.pdf, include le directory che li contengono ed esclude 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 il --Prune-empty-dirs opzione (non è una soluzione universale poiché non è possibile copiare una directory anche abbinandola in modo esplicito, ma è un requisito raro).

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

L'impostazione predefinita è includere tutto, quindi è necessario escludere esplicitamente tutto after compresi 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 '*'.

30
jmanning2k

Se usi un modello come *.pdf, Shell "espande" quel 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 ** pattern può essere utilizzato per abbinare ricorsivamente le cartelle. Prova questo:

rsync -avn ~/LaTeX/**/*.pdf ~/Output/
15
Marcel Stimberg

Puoi usare find e 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.

13
Derek Frye

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 critica tra questa e la risposta di kbrd è il --include="*/" flag, che dice a rsync di andare avanti e copiare tutte le directory che trova, qualunque esse siano chiamate. Questo è necessario perché rsync non ricorre in una sottodirectory a meno che non sia stato incaricato di copiare quella sottodirectory.

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

  1. Avere successo 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).

9
SamB

Questa è la mia soluzione preferita:

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

Il comando find è più semplice da comprendere rispetto alle regole include/exclude di rsync :-)

Se vuoi copiare solo file pdf, basta cambiare .jpg per .pdf

3
guettli

Cosa ne pensi di questo:

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

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.

2
Steven D

Per generare una directory contenente solo le intestazioni (../include) all'interno della directory di origine:

rsync -avh --Prune-empty-dirs --exclude="build" --include="*/" --include="*.h" --exclude="*" ./* ../include/

Ciò esclude tutte le directory vuote e la directory build

0
SCG82