Suggerirei di utilizzare l'opzione filtro di rsync. Per il tuo esempio digita semplicemente:
rsync -vam -f'+ *[Nn][Aa][Mm][E]*' -f'+ */' -f'- *' a b
la prima regola di filtro indica a rsync quali pattern includere. La seconda regola è necessaria per dire a rsync di ispezionare tutte le directory durante il suo attraversamento. Per impedire l'inclusione delle directory vuote, vengono escluse esplicitamente da -m
opzione. L'ultima regola di filtro dice a rsync di eliminare tutti i modelli rimanenti che ancora non corrispondevano.
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 ottenere è un elenco di modelli di inclusione accettabili per rsync, e poiché il prefisso "a/" non funziona per rsync I' lo rimuoverò con cut:
find . |
grep -i 'name' |
cut -d / -f 2-
C'è ancora un problema:mancheremo ancora i file nelle sottodirectory, perché rsync non cerca le directory nell'elenco di esclusione. Userò 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 utilizzare l'argomento --include-from=- per fornire un elenco di pattern a rsync sullo standard input. Quindi, nel complesso:
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 dei sorgenti come "./a/". Tuttavia, questo significa che il comando cut deve cambiare poiché ci sarà un "./" in più davanti ai 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/
Se usi ZSH, puoi usare 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 normale percorso ma hanno un ~
iniziale$ touch aa ab ac
$ ls *~*c
aa ab
Puoi concatenare le esclusioni:
$ ls *~*c~*b
aa
Infine puoi specificare che tipo di file vuoi restituire (directory, file, ecc.). Questo viene fatto con (/) per directory e (.) per file.
$ touch file
$ mkdir dir
$ ls *(.)
file
Sulla base di tutto questo, farei quel comando come:
rsync -avvz *(/) (#i)*name* ./a/ ./b/
(Non vedo la necessità di un'esclusione con questi selettori)