find
(для -name
/ -path
стандартних предикатів) використовує шаблони підстановок так само, як глобуси (зверніть увагу, що {a,b}
це не глобальний оператор; після розширення ви отримуєте два глобуси). Основна відмінність - поводження з косою рисою (а також крапки з файлами та брудом, за якими спеціально не обробляються find
). *
в глобусах не буде охоплено декілька каталогів. */*/*
призведе до переліку до двох рівнів каталогів. Додавання -path './*/*/*'
відповідатиме будь-яким файлам, що мають глибину щонайменше трьох рівнів, і не зупинятиметься find
перелічувати вміст будь-якого каталогу на будь-якій глибині.
Для конкретного
./foo*bar/quux[A-Z]{.bak,}/pic[0-9][0-9][0-9][0-9]?.jpg
кілька глобусів, це легко перекласти, ви хочете мати каталоги на глибині 3, щоб ви могли використовувати:
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 {} +
(або -depth 3
з деякими find
реалізаціями). Або 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 {} +
Що гарантувало б, що ті *
і ?
не могли відповідати /
персонажам.
( find
всупереч глобусам буде читати вміст каталогів, відмінних від foo*bar
поточного в каталозі¹, а не сортувати список файлів. Але якщо ми залишимо осторонь, що те, що відповідає [A-Z]
або поведінка *
/ ?
щодо недійсних символів, - це не вказано, ви отримаєте той самий список файлів).
Але в будь-якому випадку, як показало @muru , не потрібно вдаватися, find
якщо це лише для розбиття списку файлів на кілька запусків, щоб обійти межу execve()
системного виклику. Деякі оболонки типу zsh
(з zargs
) або ksh93
(з command -x
) навіть мають вбудовану підтримку для цього.
З zsh
(чиї кульками також мають еквівалент -type f
і більшість інших find
предикатів), наприклад:
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)
Є оператором Глоб всупереч {,.bak}
, то (.)
Глоб класифікатор є еквівалентом find
«s -type f
, додайте oN
туди , щоб пропустити сортування , як з find
, D
щоб включити дот-файли (не відноситься до цього Glob))
¹ Щоб find
сканувати дерево каталогів, як глобуси, вам знадобиться щось на зразок:
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 \) \)
Тобто обрізайте всі каталоги на рівні 1, крім foo*bar
тих, і всі на рівні 2, окрім quux[A-Z]
або quux[A-Z].bak
, та виберіть pic...
їх на рівні 3 (та обріжте всі каталоги на цьому рівні).
-path
або-ipath
.find . -path './foo*bar/quux[A-Z]/pic[0-9][0-9][0-9][0-9]?.jpg'
повинен працювати - крім того, що це буде відповідати/fooz/blah/bar/quuxA/pic1234d.jpg
. Це буде проблема?