rsync utilizza regex per includere solo alcuni file


11

Sto cercando di eseguire rsync per copiare alcuni file in modo ricorsivo lungo un percorso in base al loro modello di nome file, senza distinzione tra maiuscole e minuscole . Questo è quello che ho fatto per eseguire rsync:

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

Non viene copiato nulla, l'output di debug mostra:

[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 *

Ho provato a usare: --include='*[Nn][Aa][Mm][E]*'e altre combinazioni, ma non funziona ancora.

Qualche idea su come usare regex per includere alcuni file?


4
Perché stai usando il --exclude='*'?

2
quindi esclude tutto ciò che non fa parte dell'inclusione.

'nascondere il file 1Name.txt a causa del modello ' questo indica: - "questa regola --esclude deve essere nel comando?" oppure Se vuoi escludere alcuni file, allora perché un " ".
Akshay Patil,

Risposte:


5

rsync non parla regex. Puoi arruolare find e grep, anche se diventa un po 'arcano. Per trovare i file di destinazione:

find a/ |
grep -i 'name'

Ma hanno tutti il ​​prefisso "a /" - il che ha senso, ma quello che vogliamo finire è un elenco di modelli di inclusione accettabili per rsync, e poiché il prefisso "a /" non funziona per rsync I ' Lo rimuoverò con il taglio:

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

C'è ancora un problema: ci mancheranno ancora i file nelle sottodirectory, perché rsync non cerca le directory nell'elenco di esclusione. Ho intenzione di utilizzare awk per aggiungere le sottodirectory di tutti i file corrispondenti all'elenco dei modelli di inclusione:

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

Non resta che inviare l'elenco a rsync - possiamo usare l'argomento --include-from = - per fornire un elenco di schemi da rsync sull'input standard. Quindi, complessivamente:

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

Si noti che la directory di origine 'a' viene indicata tramite due percorsi diversi: "a /" e "./a/". Questo è sottile ma importante. Per rendere le cose più coerenti, farò un'ultima modifica e farò sempre riferimento alla directory di origine come "./a/". Tuttavia, questo significa che il comando cut deve cambiare in quanto ci sarà un ulteriore "./" sulla parte anteriore dei risultati di find:

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

Ho provato a eseguirlo, ho riscontrato problemi con il comando cut. Sembra che -tsia un interruttore valido.

modifica: intendevo -t non è un interruttore valido

scusa, dovrebbe essere -d. ho iniziato a usare sed e poi sono passato a tagliare perché pensavo fosse più chiaro, ma ho dimenticato di modificare i miei comandi: S

Seguito: ho provato a modificare lo script per prendere argomenti ($ 1 = path_to_search, $ 2 come modello per egrep) mentre sto abbinando il nome file + mix di estensioni. Quelle parti funzionano bene, ho ottenuto l'elenco previsto, tuttavia rsync non riesce a copiare. Sembra funzionare solo con la directory dei caratteri a nome singolo come nell'esempio (a) la mia ipotesi è che il comando cut deve essere modificato per tagliare i caratteri in base alla directory principale / sorgente? Un po 'perso di come farlo:
user1957413

Ah sì, hai ragione. Dovrebbe funzionare su un nome di directory di qualsiasi lunghezza, ma non riuscirà non appena si fa riferimento a una directory esterna alla directory corrente (poiché nella parte del prefisso ci sarà un numero diverso di barre). Per risolvere il problema, probabilmente è più facile usare sed invece di cut, come: sed "s#^$1/*##" buuuut che si interromperà su percorsi che contengono un #. Per risolvere il problema, dobbiamo citare il nome della directory in entrata: prefix=$(echo "$1" | sed 's#/#\\/#g')e quindi sed "s/^$prefix\\/*//" Le sottigliezze della citazione in bash sono un po 'un incubo;)
sqweek

7

Vorrei suggerire di utilizzare l'opzione di filtro di rsync. Per il tuo esempio basta digitare:

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

la prima regola di filtro dice a rsync quali schemi includere. La seconda regola è necessaria per dire a rsync di ispezionare tutte le directory sulla sua traversata. Per impedire l'inclusione delle directory vuote, vengono escluse esplicitamente -mdall'opzione. L'ultima regola del filtro dice a rsync di eliminare tutti i modelli rimanenti che finora non corrispondevano.


Dolce. Anche questo ha funzionato. Stavo ottenendo la cartella a all'interno di b, che è stata riparata usando a / b / come origine e destinazione. Grazie!
user1957413

Usa -f '+ * [Nn] [Aa] [Mm] [E] **' (due stelle alla fine) per includere i contenuti di tutte le directory con un nome specifico.
fobico

2

Se si utilizza ZSH, è possibile utilizzare il flag (#i) per disattivare la distinzione tra maiuscole e minuscole. Esempio:

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

ZSH supporta anche le esclusioni, che sono specificate proprio come il percorso normale ma hanno un ~ iniziale

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

Puoi concatenare le esclusioni:

$ ls *~*c~*b
aa

Infine puoi specificare quale tipo di file vuoi restituire (directory, file, ecc.). Questo viene fatto con (/) per la directory e (.) Per il file.

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

Sulla base di tutto ciò, farei quel comando come:

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

(Non vedo la necessità di un'esclusione con questi selettori)


1

La risposta di @ sqweek sopra è fantastica, anche se sospetto che abbia un bug nel suo awkscript per la generazione di directory principali, come mi dà ad esempio:

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

Sono stato in grado di risolverlo utilizzando gensubinvece:

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

Quindi, la sua soluzione completa, con il awkbit cambiato, sarebbe:

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/

Grazie. Modificata la mia risposta con la correzione equivalente di ancoraggio del regex alla fine della riga ( sub("/[^/]*$")).
sqweek,

0

Ho provato con uno script C # poiché è il linguaggio con cui ho più esperienza. Sono in grado di creare l'elenco dei file che voglio includere, ma qualcuno rsync mi sta ancora dicendo di fare un'escursione. Crea le cartelle, ma ignora i file. Ecco cosa è quello che ho ..

Innanzitutto il contenuto della directory:

~/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

Quindi l'output dello script C #:

~/mono$ mono test.exe

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

E l'output di debug:

~/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 *

0

[EDIT] Funziona solo localmente. Per i percorsi remoti, è necessario prima creare la struttura di directory.

Più semplice della risposta accettata; Usa --file-from, che include automaticamente le directory principali e stampa il percorso del file con% P

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

Quindi devi solo usare finde rsync.

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.