У меня снова и снова возникала такая проблема: у меня есть глобус, который точно соответствует правильным файлам, но вызывает Command line too long
. Каждый раз, когда я преобразовывал это в некоторую комбинацию, find
и grep
это работает для конкретной ситуации, но это не на 100% эквивалентно.
Например:
./foo*bar/quux[A-Z]{.bak,}/pic[0-9][0-9][0-9][0-9]?.jpg
Есть ли инструмент для преобразования глобусов в find
выражения, о которых я не знаю? Или есть вариант для find
сопоставления глоба без совпадения с тем же глобусом в поддиректории (например foo/*.jpg
, не разрешено совпадать bar/foo/*.jpg
)?
-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
. Это будет проблемой?echo <glob> | cat
, предполагая мои знания bash, echo является встроенным и, следовательно, не имеет максимального командного лимитаОтветы:
Если проблема заключается в том, что вы получаете ошибку аргумента list-is-too-long, используйте цикл или встроенную оболочку. Хотя
command glob-that-matches-too-much
может выдавать ошибку,for f in glob-that-matches-too-much
нет, так что вы можете просто сделать:Цикл может быть мучительно медленным, но он должен работать.
Или:
(
printf
будучи встроенным в большинство оболочек, вышеприведенное работает вокруг ограниченияexecve()
системного вызова)Также работает с Bash. Я не уверен точно, где это задокументировано, хотя.
И Vim,
glob2regpat()
и Pythonfnmatch.translate()
могут конвертировать глобусы в регулярные выражения, но оба также используют.*
для*
сопоставления по всему/
.источник
something
сecho
должен сделать это.printf
- это будет быстрее, чем звонитьecho
тысячи раз, и предлагает большую гибкость.exec
, которое применяется к внешним командам, таким какcat
; но это ограничение не относится к встроенным командам оболочки, таким какprintf
.printf
она является встроенной, и оболочки, вероятно, используют тот же метод для предоставления ей аргументов, что и для перечисления аргументовfor
.cat
не является встроеннымmksh
гдеprintf
не встроено» и оболочки типа «ksh93
где»cat
(или может быть) встроено. Смотрите такжеzargs
вzsh
работать вокруг него , без необходимости прибегать кxargs
.find
(для предикатов-name
/-path
standard) используются шаблоны с подстановочными знаками, аналогично globs (обратите внимание, что{a,b}
это не оператор glob; после расширения вы получите два glob). Основным отличием является обработка слешей (и файлов с точками и директорий, которые не обрабатываются специальноfind
).*
в шарах не будет охватывать несколько каталогов.*/*/*
приведет к перечислению до 2 уровней каталогов. Добавление-path './*/*/*'
будет соответствовать любым файлам глубиной не менее 3-х уровней и не остановитfind
перечисление содержимого любого каталога на любой глубине.Для этого конкретного
пара глобусов, их легко перевести, вам нужны каталоги на глубине 3, поэтому вы можете использовать:
(или
-depth 3
с некоторымиfind
реализациями). Или положительно:Который гарантировал бы, что те
*
и другие?
не могли соответствовать/
персонажам.(в
find
отличие от globs прочитал бы содержимое каталогов, отличныхfoo*bar
от текущего каталога¹, и не отсортировал бы список файлов. Но если мы оставим в стороне проблему, то, что соответствует[A-Z]
или поведение*
/ в?
отношении недопустимых символов, не указано, вы получите тот же список файлов).Но в любом случае, как показало @muru , нет необходимости прибегать к помощи,
find
если это просто для разделения списка файлов на несколько прогонов, чтобы обойти ограничениеexecve()
системного вызова. Некоторые оболочки, такие какzsh
(сzargs
) илиksh93
(сcommand -x
), даже имеют встроенную поддержку для этого.С
zsh
(чьи глобусы также имеют эквивалент-type f
и большинство другихfind
предикатов), например:(
(|.bak)
оператор glob противоречит{,.bak}
,(.)
квалификатор glob является эквивалентомfind
's'-type f
, добавьтеoN
туда, чтобы пропустить сортировку, напримерfind
,D
с включением точек-файлов (не относится к этому глобу))¹ Для того,
find
чтобы сканировать дерево каталогов, как глобусы, вам нужно что-то вроде:Это означает удаление всех каталогов на уровне 1, за исключением
foo*bar
тех, и все на уровне 2, за исключениемquux[A-Z]
илиquux[A-Z].bak
, и затем выберитеpic...
те на уровне 3 (и удалите все каталоги на этом уровне).источник
Вы можете написать регулярное выражение для поиска соответствия вашим требованиям:
источник
.
, добавить дополнительный матч за.bak
и изменения*
к[^/]*
не совпадают пути , как / Foo / Foo / бар и т.д.[0-9][0-9][0-9][0-9]?
до[0-9]{3,4}
Обобщая примечание к моему другому ответу , в качестве более прямого ответа на ваш вопрос, вы можете использовать этот
sh
скрипт POSIX для преобразования глобуса вfind
выражение:Для использования с одним стандартным
sh
глобаном (не для двух глобусов вашего примера, в которых используется расширение скобок ):(это не игнорирует точечные файлы или точечные каталоги, кроме как
.
и..
не сортирует список файлов).Он работает только с глобусами относительно текущего каталога, без
.
или с..
компонентами. Приложив некоторые усилия, вы можете распространить его на любой глобус, более чем глобус ... Это также можно оптимизировать, чтобыglob2find 'dir/*'
он не выглядел такdir
же, как для шаблона.источник