rsync kopiuje tylko niektóre typy plików przy użyciu opcji dołączania

110

Używam następującego skryptu bash, aby kopiować tylko pliki o określonym rozszerzeniu (w tym przypadku * .sh), jednak nadal kopiuje wszystkie pliki. Co jest nie tak?

from = 1 $
to = 2 $

rsync -zarv --include = "*. sh" $ od $ do
user881480
źródło
4
Chociaż nie jest to ściśle powiązane, sugerowałbym cytowanie $ od / $ do. Niezrobienie tego może dać nieoczekiwane rezultaty, jeśli argumenty pozycyjne 1/2 zawierają spacje.
Kjetil Joergensen
czy zrozumiałeś, dlaczego twoje polecenie nie zadziała?
Charlie Parker
@CharlieParker: Czy musisz użyć rsync, można to bardzo dobrze osiągnąć za pomocą elementów wewnętrznych powłoki?
Inian
To, czego brakuje w tym pytaniu i jego odpowiedziom, to jak stworzyć polecenie, jeśli mam katalogi rekurencyjne, do których chcę wysłać tylko jeden typ pliku. Wygląda na to, że robi to tylko dla katalogu docelowego ...
Charlie Parker

Odpowiedzi:

200

Myślę, że --includejest używany do włączania podzbioru plików, które w przeciwnym razie są wykluczone przez --exclude, a nie tylko do tych plików. Innymi słowy: musisz pomyśleć o uwzględnieniu znaczenia , a nie wykluczaniu .

Spróbuj zamiast tego:

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

W przypadku rsync w wersji 3.0.6 lub nowszej kolejność należy zmodyfikować w następujący sposób (patrz komentarze):

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

Dodanie -mflagi pozwoli uniknąć tworzenia pustych struktur katalogów w miejscu docelowym. Przetestowano w wersji 3.1.2.

Więc jeśli chcemy tylko plików * .sh, musimy wykluczyć wszystkie pliki --exclude="*", dołączyć wszystkie katalogi --include="*/"i dołączyć wszystkie pliki * .sh --include="*.sh".

Możesz znaleźć dobre przykłady w sekcji Include / Exclude Pattern Rules na stronie podręcznika

Chepner
źródło
10
Chociaż dostaniesz wszystkie podkatalogi, jeśli są jakieś pliki .sh w podkatalogach, które chcesz rsync, prawdopodobnie będziesz też chciał użyć --include = "* /".
Kjetil Joergensen
50
Wypróbowałem to na rsync w wersji 3.0.7, którą dostałem dawno temu z macports, i nie działało z taką kolejnością włączeń / wykluczeń. To, co skończyło się, że pracował dla mnie (dostosowany do OP) rsync -zarv --include="*/" --include="*.sh" --exclude="*" "$from" "$to".
Bijou Trouvaille
3
Próbowałem z rsync 3.0.9 i to nie działa. Bijou ma rację, kolejność nie jest właściwa (pierwszy --include=\*.shwtedy --exclude=\*)
TrueY
3
Zauważ, że zawsze możesz kliknąć edytuj i zasugerować zmianę w odpowiedzi :)
Achal Dave,
2
Nie działa w przypadku zamawiania włączeń / wykluczeń, ale działa z kolejnością sugerowaną przez Bijou Trouvaille
John Smith Opcjonalnie
57

Odpowiedź @chepner skopiuje wszystkie podkatalogi, niezależnie od tego, czy zawiera plik, czy nie. Jeśli chcesz wykluczyć podkatalogi, które nie zawierają pliku i nadal zachowują strukturę katalogów, użyj

rsync -zarv  --prune-empty-dirs --include "*/"  --include="*.sh" --exclude="*" "$from" "$to"
WanderingMind
źródło
1
To był dla mnie wymóg: „Jeśli chcesz wykluczyć podkatalogi, które nie zawierają pliku i nadal zachowują strukturę katalogów” +1
Juuso Ohtonen
1
Nie rozumiem, skąd wiedziałeś, jaka była kolejność - zawiera?
Charlie Parker
1
W jaki sposób można utworzyć polecenie, jeśli mam katalogi rekurencyjne, do których chcę wysłać tylko jeden typ pliku. Wygląda na to, że robi to tylko dla katalogu docelowego.
Charlie Parker
15

Jeszcze jeden dodatek: jeśli chcesz synchronizować pliki według ich rozszerzeń tylko w jednym katalogu (bez rekursji), powinieneś użyć takiej konstrukcji:

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

Zwróć uwagę na kropkę w pierwszej --include. --no-rnie działa w tej konstrukcji.

EDYTOWAĆ:

Dzięki gbyte.co za cenny komentarz!

Serge Roussak
źródło
1
skąd wiedziałeś, jaka musi być kolejność flag i co powinny zawierać?
Charlie Parker
1
@CharlieParker, ponieważ wykorzystuje tworzenia serwerów includei excludeopcji w kolejności, w jakiej zostały one określonego w. Poza tym, że zatrzymuje się na pierwszym dopasowane jeden. Tak więc, jeśli określimy --exclude '*'na pierwszym miejscu w tym przykładzie, rsync nic nie zrobi. Zobacz mężczyznę, aby uzyskać więcej wyjaśnień.
Serge Roussak
czy możesz mi wyjaśnić, co robi każda flaga? Pierwsza flaga -- include './' mówi, że zawierać wszystko w ścieżce katalogu źródłowego? Następnie następny `--include '.ext' 'zawiera określony plik w ścieżce źródłowej o nazwie, .exta następnie wykluczenie mówi, że nie wysyłać niczego więcej --exclude '*'? Czy to jest poprawne?
Charlie Parker
1
W jaki sposób można utworzyć polecenie, jeśli mam katalogi rekurencyjne, do których chcę wysłać tylko jeden typ pliku. Wygląda na to, że robi to tylko dla katalogu docelowego.
Charlie Parker
1
Dzięki za to! Musi --include '*.ext'i nie--include '.ext'
GB
13

Oto ważna część strony podręcznika:

W miarę budowania listy plików / katalogów do przesłania rsync sprawdza po kolei każdą nazwę do przesłania z listą wzorców włączania / wykluczania i wykonywany jest pierwszy pasujący wzorzec: jeśli jest to wzorzec wykluczania, plik ten jest pominięty; jeśli jest to wzorzec włączania, to nazwa pliku nie jest pomijana; jeśli nie zostanie znaleziony pasujący wzorzec, to nazwa pliku nie jest pomijana.

Podsumowując:

  • Brak dopasowania do żadnego wzorca oznacza, że ​​plik zostanie skopiowany!
  • Algorytm kończy działanie po dopasowaniu dowolnego wzorca

Ponadto coś kończącego się ukośnikiem to dopasowywanie katalogów (tak jak find -type dby).

Oddzielmy tę odpowiedź od góry.

rsync -zarv  --prune-empty-dirs --include "*/"  --include="*.sh" --exclude="*" "$from" "$to"
  1. Nie pomijaj żadnych katalogów
  2. Nie pomijaj żadnych .shplików
  3. Pomiń wszystko
  4. (Niejawnie nie pomijaj niczego, ale powyższa reguła zapobiega wystąpieniu reguły domyślnej).

Wreszcie, --prune-empty-directoriespierwsza reguła zapobiega tworzeniu pustych katalogów w każdym miejscu.

Jim Hunziker
źródło
Dziękuję bardzo za wyjaśnienie, co się dzieje. Teraz jest znacznie większa szansa, że ​​nie zapomnę polecenia.
MohamedEzz
3
„Algorytm kończy pracę, gdy którykolwiek wzorzec pasuje” - to jest kluczowe i żadna z wyżej ocenianych odpowiedzi nie wyjaśnia tego tak jasno i z góry, jak tutaj. Oczywiście jest to gdzieś na stronie podręcznika, a jeśli ja przeczytałbym wszystko uważnie, widziałem to. Mimo to, dzięki.
TheDudeAbides
0

Jeśli ktoś szuka tego… chciałem zsynchronizować tylko określone pliki i foldery i udało mi się to zrobić tym poleceniem: rsync --include-from=rsync-files

Z plikami rsync:

my-dir/
my-file.txt

- /*
Pascal Polleunus
źródło
0

Napisałem tę przydatną funkcję i umieściłem w moich skryptach bash lub ~/.bash_aliases. Przetestowano synchronizację lokalną w systemie Linux z awkzainstalowanym bashem . To działa

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
}

Zalety:

krótki, poręczny i rozszerzalny, gdy chce się dodać więcej argumentów (np --dry-run .).

Przykład:

selrsync 'tsv,csv' ./source ./target --dry-run
biocyberman
źródło