rsync używa wyrażenia regularnego, aby dołączyć tylko niektóre pliki

11

Próbuję uruchomić rsync, aby skopiować rekursywnie niektóre pliki w dół ścieżki na podstawie wzorca nazwy pliku, bez rozróżniania wielkości liter . Oto, co zrobiłem, aby uruchomić rsync:

$ rsync -avvz --include ='*/' --include='.*[Nn][Aa][Mm][E].*' --exclude='*' ./a/ ./b/

Nic się nie kopiuje, dane wyjściowe debugowania pokazują:

[sender] hiding file 1Name.txt because of pattern *
[sender] hiding file 1.txt because of pattern *
[sender] hiding file 2.txt because of pattern *
[sender] hiding file Name1.txt because of pattern *
[sender] hiding directory test1 because of pattern *
[sender] hiding file NaMe.txt because of pattern *

Próbowałem użyć: --include='*[Nn][Aa][Mm][E]*'i innych kombinacji, ale nadal nie działa.

Jakieś pomysły na użycie wyrażenia regularnego w celu włączenia niektórych plików?

użytkownik1957413
źródło
4
Dlaczego korzystasz z --exclude='*'?
2
więc wyklucza wszystko, co nie jest częścią uwzględnienia.
„ukrywanie pliku 1Name.txt z powodu wzorca ” oznacza: - „czy to - wykluczenie reguły musi znajdować się w poleceniu?” lub Jeśli chcesz wykluczyć niektóre pliki, to dlaczego „ ”.
Akshay Patil

Odpowiedzi:

5

rsync nie mówi wyrażenia regularnego. Możesz zaciągnąć się do szukania i grep, choć robi się to trochę tajemnicze. Aby znaleźć pliki docelowe:

find a/ |
grep -i 'name'

Ale wszystkie mają przedrostek „a /” - co ma sens, ale chcemy, aby to była lista wzorców dołączania akceptowanych przez rsync, a ponieważ przedrostek „a /” nie działa dla rsync I ” Usunę to za pomocą cięcia:

find . |
grep -i 'name' |
cut -d / -f 2-

Nadal jest problem - nadal będziemy pomijać pliki w podkatalogach, ponieważ rsync nie przeszukuje katalogów na liście wykluczeń. Użyję awk, aby dodać podkatalogi dowolnych pasujących plików do listy wzorców dołączania:

find a/ |
grep -i 'name' |
cut -d / -f 2- |
awk -F/ '{print; while(/\//) {sub("/[^/]*$", ""); print}}'

Pozostało tylko wysłać listę do rsync - możemy użyć argumentu --include-from = -, aby dostarczyć listę wzorców do rsync na standardowym wejściu. Tak więc w sumie:

find a/ |
grep -i 'name' |
cut -d / -f 2- |
awk -F/ '{print; while(/\//) {sub("/[^/]*$", ""); print}}' |
rsync -avvz --include-from=- --exclude='*' ./a/ ./b/

Zauważ, że do katalogu źródłowego „a” odwołuje się dwie różne ścieżki - „a /” i „./a/”. To jest subtelne, ale ważne. Aby wszystko było bardziej spójne, dokonam ostatniej zmiany i zawsze będę odnosił się do katalogu źródłowego jako „./a/”. Oznacza to jednak, że polecenie cięcia musi się zmienić, ponieważ z przodu wyników wyszukiwania znajdzie się dodatkowy „./”.

find ./a/ |
grep -i 'name' |
cut -d / -f 3- |
awk -F/ '{print; while(/\//) {sub("/[^/]*$", ""); print}}' |
rsync -avvz --include-from=- --exclude='*' ./a/ ./b/
sqweek
źródło
Próbowałem go uruchomić, wystąpiły problemy z poleceniem cięcia. Wydaje się, -tże to prawidłowy przełącznik.
edit: miałem na myśli, że -t nie jest prawidłowym przełącznikiem
przepraszam, powinno być -d. zacząłem używać sed, a potem zmieniłem na cut, ponieważ myślałem, że to jest bardziej zrozumiałe, ale zapomniałem edytować moich poleceń: S
Kontynuacja: Próbowałem edytować skrypt, aby wziąć argumenty ($ 1 = ścieżka_do_wyszukiwania, 2 $ jako wzorzec dla egrep), ponieważ dopasowuję nazwę pliku + mieszankę rozszerzeń. Że części działają dobrze, mam spodziewaną listę, jednak rsync nie kopiuje. Wydaje się, że działa tylko z katalogiem znaków o pojedynczej nazwie, jak w przykładzie (a) Domyślam się, że polecenie cut musi zostać zmodyfikowane, aby wycinać znaki na podstawie katalogu nadrzędnego / źródłowego? Trochę straciło to jak to zrobić:
1957413
Ach tak, masz całkowitą rację. Powinien działać na nazwie katalogu o dowolnej długości, ale zakończy się niepowodzeniem, gdy tylko odniesiesz się do katalogu poza bieżącym katalogiem (ponieważ w części przedrostka będzie inna liczba ukośników). Aby to naprawić, prawdopodobnie najłatwiej jest użyć sed zamiast cut, na przykład: sed "s#^$1/*##" buuuut, który zepsuje się na ścieżkach zawierających #. Aby to naprawić, musimy zacytować nazwę przychodzącego katalogu: prefix=$(echo "$1" | sed 's#/#\\/#g')a następnie sed "s/^$prefix\\/*//" podniosłości cytowania bash są trochę koszmarem;)
sqweek
7

Sugerowałbym użyć opcji filtrowania rsync. Na przykład wpisz:

rsync -vam -f'+ *[Nn][Aa][Mm][E]*' -f'+ */' -f'- *' a b

pierwsza reguła filtra mówi rsync, jakie wzorce należy uwzględnić. Druga reguła jest potrzebna, aby powiedzieć rsync, aby sprawdził wszystkie katalogi podczas jego przechodzenia. Aby zapobiec włączeniu pustych katalogów, są one jawnie wykluczane przez -mopcję. Ostatnia reguła filtra mówi rsync, aby pozbyła się wszystkich pozostałych wzorców, które do tej pory nie pasowały.

sparkie
źródło
Słodkie. To też działało. Otrzymałem folder a wewnątrz b, który został naprawiony przez użycie a / b / jako źródła i celu. Dzięki!
user1957413,
Użyj -f '+ * [Nn] [Aa] [Mm] [E] **' (dwie gwiazdki na końcu), aby dołączyć zawartość wszystkich katalogów o określonej nazwie.
fobiczny
2

Jeśli używasz ZSH, możesz użyć flagi (#i), aby wyłączyć rozróżnianie wielkości liter. Przykład:

$ touch NAME
$ ls (#i)*name*
NAME

ZSH obsługuje również wykluczenia, które są określone tak jak zwykła ścieżka, ale mają początkowe ~

$ touch aa ab ac
$ ls *~*c
aa ab

Możesz łączyć wykluczenia:

$ ls *~*c~*b
aa

Na koniec możesz określić, jaki rodzaj pliku chcesz zwrócić (katalog, plik itp.). Odbywa się to za pomocą (/) dla katalogu i (.) Dla pliku.

$ touch file
$ mkdir dir
$ ls *(.)
file

W oparciu o to wszystko wykonałbym to polecenie jako:

rsync -avvz *(/) (#i)*name* ./a/ ./b/

(Nie widzę potrzeby wyłączenia z tych selektorów)

Matthew Franglen
źródło
1

Powyższa odpowiedź na @ sqweek jest niesamowita, ale podejrzewam, że ma błąd w awkskrypcie do generowania katalogów nadrzędnych, ponieważ daje mi np .:

$ echo a/b/c/d | awk -F/ '{print; while(/\//) {sub("/[^/]*", ""); print}}'
a/b/c/d
a/c/d
a/d
a

Byłem w stanie to naprawić, używając gensubzamiast tego:

$ echo a/b/c/d | awk -F/ '{print; while(/\//) { $0=gensub("(.*)/[^/]*", "\\1", "g"); print}}'
a/b/c/d
a/b/c
a/b
a

Tak więc jego pełne rozwiązanie, ze awkzmienionym bitem, brzmiałoby:

find ./a/ |
grep -i 'name' |
cut -d / -f 3- |
awk -F/ '{print; while(/\//) { $0=gensub("(.*)/[^/]*", "\\1", "g"); print}}' |
rsync -avvz --include-from=- --exclude='*' ./a/ ./b/
Ryan Williams
źródło
Dzięki. Edytowałem moją odpowiedź z równoważną poprawką zakotwiczenia wyrażenia regularnego na końcu linii ( sub("/[^/]*$")).
sqweek
0

Wypróbowałem ze skryptem C #, ponieważ jest to język, z którym mam największe doświadczenie. Jestem w stanie stworzyć listę plików, które chcę dołączyć, ale ktoś rsync wciąż mówi mi, żeby wziął udział w wędrówce. Tworzy foldery, ale ignoruje pliki. Oto co mam ...

Najpierw zawartość katalogu:

~/mono$ ls -l
total 24
drwxr-xr-x 5 me me 4096 Jan 15 00:36 a
drwxr-xr-x 2 me me 4096 Jan 15 00:36 b
drwxr-xr-x 3 me me 4096 Jan 14 00:31 bin
-rw-r--r-- 1 me me 3566 Jan 15 00:31 test.cs
-rwxr-xr-x 1 me me 4096 Jan 15 00:31 test.exe
-rwxr--r-- 1 me me  114 Jan 14 22:40 test.sh

Następnie dane wyjściowe skryptu C #:

~/mono$ mono test.exe

/a/myfile/myfileseries.pdf
/a/myfile2/testfile.pdf

I dane wyjściowe debugowania:

~/mono$ mono test.exe | rsync -avvvz --include='*/' --include-from=- --exclude='*' ./a/ ./b/
[client] add_rule(+ */)
[client] parse_filter_file(-,20,3)
[client] add_rule(+ /a/myfile/myfileseries.pdf)
[client] add_rule(+ /a/myfile2/testfile.pdf)
[client] add_rule(- *)
sending incremental file list
[sender] make_file(.,*,0)
[sender] hiding file 1Name.txt because of pattern *
[sender] showing directory myfile2 because of pattern */
[sender] make_file(myfile2,*,2)
[sender] hiding file 1.txt because of pattern *
[sender] hiding file 2.txt because of pattern *
[sender] hiding file Name1.txt because of pattern *
[sender] showing directory test1 because of pattern */
[sender] make_file(test1,*,2)
[sender] hiding file NaMe.txt because of pattern *
[sender] showing directory myfile because of pattern */
[sender] make_file(myfile,*,2)
send_file_list done
send_files starting
[sender] hiding file myfile/myfileseries.pdf because of pattern *
[sender] hiding file myfile2/testfile.pdf because of pattern *
[sender] hiding file test1/test.txt because of pattern *
użytkownik1957413
źródło
0

[EDYCJA] Działa to tylko lokalnie. W przypadku ścieżek zdalnych najpierw należy utworzyć strukturę katalogów.

Prostsze niż zaakceptowana odpowiedź; Użyj --file-from, który automatycznie zawiera katalogi nadrzędne i printf ścieżkę pliku za pomocą% P

find /tmp/source -wholename '*[Nn][Aa][Mm][E]*' -printf '%P\n' | rsync -vzrm --exclude='*/' --files-from=- /tmp/source/ /tmp/target/

Musisz tylko użyć findi rsync.

fobiczny
źródło