rsync copia solo su alcuni tipi di file usando l'opzione include


110

Uso il seguente script bash per copiare solo file di una certa estensione (in questo caso * .sh), tuttavia copia ancora su tutti i file. Cosa c'è che non va?

da = $ 1
a = $ 2

rsync -zarv --include = "*. sh" $ da $ a

4
Sebbene non sia strettamente correlato, suggerirei di citare $ da / $ a. Non farlo potrebbe dare risultati inaspettati se gli argomenti posizionali 1/2 includono spazi.
— Kjetil Joergensen

hai capito perché il tuo comando non funzionerebbe?
— Charlie Parker

@CharlieParker: devi usare rsync, questo può essere ottenuto molto bene con gli interni della shell?
— Inian

Ciò che manca a questa domanda e alle sue risposte è come creare il comando se ho directory ricorsive che voglio inviare solo un tipo di file. Sembra che lo faccia solo per la directory di destinazione ...
— Charlie Parker

Risposte:


200

Penso che --includesia usato per includere un sottoinsieme di file che sono altrimenti esclusi da --exclude, piuttosto che includere solo quei file. In altre parole: devi pensare a includere il significato non escludere .

Prova invece:

rsync -zarv  --include "*/" --exclude="*" --include="*.sh" "$from" "$to"

Per rsync versione 3.0.6 o successiva, l'ordine deve essere modificato come segue (vedi commenti):

rsync -zarv --include="*/" --include="*.sh" --exclude="*" "$from" "$to"

L'aggiunta del -mflag eviterà di creare strutture di directory vuote nella destinazione. Testato nella versione 3.1.2.

Quindi, se vogliamo solo file * .sh, dobbiamo escludere tutti i file --exclude="*", includere tutte le directory --include="*/"e includere tutti i file * .sh --include="*.sh".

Puoi trovare alcuni buoni esempi nella sezione Include / Exclude Pattern Rules della pagina man


10
Anche se ti porterà tutte le sottodirectory, se ci sono file .sh nelle sottodirectory che vuoi rsync, è probabile che vorrai usare anche --include = "* /".
— Kjetil Joergensen

50
Ho provato questo su rsync versione 3.0.7, che ho ottenuto molto tempo fa da macports, e non ha funzionato con questo ordine di include / esclude. Questo è quello che ho finito con che ha funzionato per me (adattato per OP): rsync -zarv --include="*/" --include="*.sh" --exclude="*" "$from" "$to".
— Bijou Trouvaille

3
Ho provato con rsync 3.0.9 e non ha funzionato. Bijou ha ragione, l'ordinamento non è corretto (prima --include=\*.shquindi --exclude=\*)
— TrueY

3
Nota che puoi sempre fare clic su Modifica e suggerire una modifica alla risposta :)
— Achal Dave

2
Non funziona con il tuo ordine di include / esclude, ma funziona con l'ordine suggerito da Bijou Trouvaille
— John Smith Opzionale

57

La risposta di @chepner copierà tutte le sottodirectory indipendentemente dal fatto che contenga o meno il file. Se è necessario escludere le sottodirectory che non contengono il file e mantengono comunque la struttura della directory, utilizzare

rsync -zarv  --prune-empty-dirs --include "*/"  --include="*.sh" --exclude="*" "$from" "$to"

1
Questo era un requisito per me: "Se devi escludere le sottodirectory che non contengono il file e mantengono comunque la struttura della directory" +1
— Juuso Ohtonen

1
Non capisco come facevi a sapere quale fosse l'ordine degli --inclusi?
— Charlie Parker

1
Come si crea il comando se ho directory ricorsive che voglio inviare solo un tipo di file. Sembra che lo faccia solo per la directory di destinazione.
— Charlie Parker

15

Un'altra aggiunta: se hai bisogno di sincronizzare i file con le sue estensioni in una sola directory (senza ricorsione) dovresti usare una costruzione come questa:

rsync -auzv --include './' --include '*.ext' --exclude '*' /source/dir/ /destination/dir/

Presta attenzione al punto nel primo --include. --no-rnon funziona in questa costruzione.

MODIFICARE:

Grazie a gbyte.co per il prezioso commento!


1
come facevi a sapere quale doveva essere l'ordine delle bandiere e cosa dovevano includere?
— Charlie Parker

1
@CharlieParker, perché il rsync usa l' includee le excludeopzioni nell'ordine cui sono stati specificati in. In aggiunta a questo, si ferma a quella prima abbinato. Quindi, se specifichiamo --exclude '*'al primo posto in questo esempio, rsync non farà nulla. Vedere l'uomo per ulteriori spiegazioni.
— Serge Roussak

puoi spiegarmi cosa sta facendo ogni bandiera? Il primo flag -- include './' sta dicendo includi tutto nel percorso della directory di origine? Quindi il prossimo `--include '.ext'` include il file specifico nel percorso di origine denominato .exte quindi l'esclusione dice non inviare nient'altro --exclude '*'? È corretto?
— Charlie Parker

1
Come si crea il comando se ho directory ricorsive che voglio inviare solo un tipo di file. Sembra che lo faccia solo per la directory di destinazione.
— Charlie Parker

1
Grazie per questo! Necessario --include '*.ext'e non--include '.ext'
— gbyte

13

Ecco la parte importante della pagina man:

Quando viene creato l'elenco di file / directory da trasferire, rsync controlla a turno ogni nome da trasferire rispetto all'elenco di modelli di inclusione / esclusione e si agisce sul primo modello di corrispondenza: se è un modello di esclusione, allora quel file è saltato; se è un pattern di inclusione, il nome del file non viene ignorato; se non viene trovato alcun modello corrispondente, il nome del file non viene ignorato.

Riassumere:

  • Non corrispondere a nessun modello significa che un file verrà copiato!
  • L'algoritmo si chiude una volta che qualsiasi pattern corrisponde

Inoltre, qualcosa che termina con una barra corrisponde alle directory (come find -type dfarebbe).

Separiamo questa risposta dall'alto.

rsync -zarv  --prune-empty-dirs --include "*/"  --include="*.sh" --exclude="*" "$from" "$to"
  1. Non saltare nessuna directory
  2. Non saltare nessun .shfile
  3. Salta tutto
  4. (Implicitamente, non saltare nulla, ma la regola sopra impedisce che la regola predefinita si verifichi.)

Infine, --prune-empty-directoriesmantiene la prima regola di creare directory vuote ovunque.


Grazie mille per aver spiegato cosa sta succedendo. Ora ci sono molte più possibilità che non dimentichi il comando.
— MohamedEzz

3
"L'algoritmo si chiude una volta che qualsiasi pattern corrisponde" : questa è la chiave, e nessuna delle risposte più apprezzate lo spiega chiaramente e in modo così chiaro come hai fatto qui. Ovviamente questo è nella pagina man da qualche parte, e se io leggerei tutto attentamente, l'avrei visto. Comunque, grazie.
— TheDudeAbides

0

Se qualcuno cerca questo ... volevo rsync solo file e cartelle specifici e sono riuscito a farlo con questo comando: rsync --include-from=rsync-files

Con i file rsync:

my-dir/
my-file.txt

- /*

0

Ho scritto questa pratica funzione e ho inserito i miei script bash o ~/.bash_aliases. Sincronizzazione testata localmente su Linux con bash e awkinstallata. Funziona

selrsync(){
# selective rsync to sync only certain filetypes;
# based on: https://stackoverflow.com/a/11111793/588867
# Example: selrsync 'tsv,csv' ./source ./target --dry-run
types="$1"; shift; #accepts comma separated list of types. Must be the first argument.
includes=$(echo $types| awk  -F',' \
    'BEGIN{OFS=" ";}
    {
    for (i = 1; i <= NF; i++ ) { if (length($i) > 0) $i="--include=*."$i; } print
    }')
restargs="$@"

echo Command: rsync -avz --prune-empty-dirs --include="*/" $includes --exclude="*" "$restargs"
eval rsync -avz --prune-empty-dirs --include="*/" "$includes" --exclude="*" $restargs
}

Avantages:

breve pratico ed estensibile quando si desidera aggiungere più argomenti (cioè --dry-run).

Esempio:

selrsync 'tsv,csv' ./source ./target --dry-run
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.