У меня есть команда find, и я хотел бы выполнить ее из произвольного каталога с $directory
переменной вместо точки .
для текущего рабочего каталога.
Что работает, так это
- Пример 1
find $directory -maxdepth 1 -type d -name "test*"
Это дает мне некоторые результаты.
Это тоже работает
- Пример 2
find . -maxdepth 1 -type d -regextype posix-extended -regex "^./[a-zA-Z0-9]+([-_]?[a-zA-Z0-9]+)*-[0-9]{1,3}(.[0-9]{1,3}){,3}\$"
Однако с a $directory
это не работает. Обратите внимание, что я удалил the ./
в начале регулярного выражения.
- Пример 3
find $directory -maxdepth 1 -type d -regextype posix-extended -regex "^[a-zA-Z0-9]+([-_]?[a-zA-Z0-9]+)*-[0-9]{1,3}(.[0-9]{1,3}){,3}\$"
Почему это так?
Спасибо
решение1
-regex
(не стандартный), как и стандартные -path
совпадения по полному пути файлов. Эти пути начинаются с содержимого , за которым $directory
следуют каталоги и файлы, найденные find
. Так что если $directory
есть /some/dir
, -regex
будет соответствовать регулярному выражению по /some/dir/file-discovered-by-find
, и никогда не будет соответствовать здесь, так как первый символ — это /
, а не alnum.
В первом случае ваше регулярное выражение начиналось с ^./
(так и должно было быть, ^\./
поскольку .
это оператор регулярного выражения или как \./
подразумевается ^
в GNU find
), -regex
поскольку $directory
там было .
.
Вам нужно сделать что-то похожее с $directory
, имея в виду, что все операторы регулярных выражений в $directory
( ^$*()+[]?.\
...) должны быть экранированы. Но здесь вы можете сделать так же:
find "$directory" -maxdepth 1 -type d -regextype posix-extended \
-regex '.*/[[:alnum:]]+([-_][[:alnum:]]+)*-[[:digit:]]{1,3}(\.[[:digit:]]{1,3}){0,3}'
(Я также заменил .
на , \.
поскольку подозреваю, что вы хотите сопоставить букву .
, а не просто любой символ, и удалил , ?
который здесь не нужен).
То есть, ваш шаблон (который здесь гарантированно не будет включать в себя /
) должен соответствовать любому /
(и до конца пути к файлу, что $
также подразумевается), а не чему-то, что соответствует $directory
.
С помощью zsh -o extendglob
вы можете сделать:
set -o extendedglob
w=[0-9a-zA-Z] d=[0-9]
print -rC1 -- $directory/$~w##([-_]$~w##)#-$~d(#c1,3)(.$~d(#c1,3))(#c0,3)(#q/)
Который имеет несколько преимуществ по сравнению с GNU find
:
- будет работать даже на не-GNU системах (устраняет зависимость от GNU
find
) - работает даже если
$directory
начинается с-
- дает вам отсортированный список
- в
zsh
, то, что[a-zA-Z0-9]
соответствует, не является случайным и не меняется в зависимости от локалей, как вfind
и соответствует символам, которые, как я полагаю, вы хотите сопоставить, и только им. Вfind
, вам нужно будет[abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789]
получить эквивалент. - это работает, даже если
$directory
это символическая ссылка на каталог (хотя вы можете добавить-H
опциюfind
для этого). - это работает, даже если пути к файлам (в данном случае содержимое
$directory
) содержат последовательность байтов, которые не образуют допустимые символы в текущей локали (find
'-regex
'.*
не могут совпадать с ними, поскольку.
соответствуют только допустимым символам). - Вместо того, чтобы печатать этот список, вы можете использовать его напрямую (в качестве аргументов команды, для выполнения цикла и т. д.)
- Вы также можете использовать такие вещи, как
(<0-255>~????*)
сопоставление десятичных чисел от 0 до 255, состоящих не более чем из 3 цифр, или(<0-255>~0?*)
для чисел без начального нуля, посколькуzsh
globs является одним из немногих API сопоставления с шаблоном, которые поддерживают сопоставление диапазонов чисел.