find
(per i predicati -name
/ -path
standard) usa modelli jolly proprio come globs (nota che {a,b}
non è un operatore glob; dopo l'espansione, ottieni due globs). La differenza principale è la gestione di barre (e file di punti e directory non trattati in modo speciale find
). *
nei globs non si estenderà su più directory. */*/*
farà elencare fino a 2 livelli di directory. L'aggiunta di a -path './*/*/*'
corrisponderà a tutti i file con almeno 3 livelli di profondità e non smetterà find
di elencare i contenuti di qualsiasi directory a qualsiasi profondità.
Per quel particolare
./foo*bar/quux[A-Z]{.bak,}/pic[0-9][0-9][0-9][0-9]?.jpg
un paio di globs, è facile da tradurre, stai cercando directory a profondità 3, quindi puoi usare:
find . -mindepth 3 -maxdepth 3 \
\( -path './foo*bar/quux[A-Z].bak/pic[0-9][0-9][0-9][0-9]?.jpg' -o \
-path './foo*bar/quux[A-Z]/pic[0-9][0-9][0-9][0-9]?.jpg' \) \
-exec cmd {} +
(o -depth 3
con alcune find
implementazioni). O POSIXly:
find . -path './*/*/*' -prune \
\( -path './foo*bar/quux[A-Z].bak/pic[0-9][0-9][0-9][0-9]?.jpg' -o \
-path './foo*bar/quux[A-Z]/pic[0-9][0-9][0-9][0-9]?.jpg' \) \
-exec cmd {} +
Il che garantirebbe che quelli *
e ?
non potrebbero abbinare i /
personaggi.
( find
contrariamente a globs leggerebbe il contenuto di directory diverse da foo*bar
quelle presenti nella directory corrente¹, e non ordinerebbe l'elenco dei file. Ma se lasciamo da parte il problema che ciò che corrisponde [A-Z]
o il comportamento di *
/ ?
rispetto ai caratteri non validi è non specificato, otterrai lo stesso elenco di file).
Ma in ogni caso, come ha dimostrato @muru , non è necessario ricorrere find
se si tratta solo di dividere l'elenco di file in più esecuzioni per aggirare il limite della execve()
chiamata di sistema. Alcune shell come zsh
(con zargs
) o ksh93
(con command -x
) hanno persino il supporto integrato per questo.
Con zsh
(i cui globs hanno anche l'equivalente -type f
e la maggior parte degli altri find
predicati), ad esempio:
autoload zargs # if not already in ~/.zshrc
zargs ./foo*bar/quux[A-Z](|.bak)/pic[0-9][0-9][0-9][0-9]?.jpg(.) -- cmd
( (|.bak)
è un operatore glob contrario {,.bak}
, il (.)
qualificatore glob è l'equivalente di find
's -type f
, aggiungilo oN
per saltare l'ordinamento come con find
, D
per includere file dot (non si applica a questo glob))
¹ Per find
eseguire la scansione dell'albero delle directory come farebbero globs, avresti bisogno di qualcosa del tipo:
find . ! -name . \( \
\( -path './*/*' -o -name 'foo*bar' -o -prune \) \
-path './*/*/*' -prune -name 'pic[0-9][0-9][0-9][0-9]?.jpg' -exec cmd {} + -o \
\( ! -path './*/*' -o -name 'quux[A-Z]' -o -name 'quux[A-Z].bak' -o -prune \) \)
Cioè potare tutte le directory al livello 1 tranne foo*bar
quelle, e tutte al livello 2 tranne le quux[A-Z]
o quux[A-Z].bak
, quindi selezionare pic...
quelle al livello 3 (e potare tutte le directory a quel livello).
-path
o-ipath
.find . -path './foo*bar/quux[A-Z]/pic[0-9][0-9][0-9][0-9]?.jpg'
dovrebbe funzionare - tranne che corrisponderà/fooz/blah/bar/quuxA/pic1234d.jpg
. Sarà un problema?