Есть ли историческая причина, почему Bash "globbing" и регулярные выражения не идентичны? Например, я считаю, что в Bash [1-2]*
совпадает все, что начинается с 1 или 2, за которым следует что-нибудь еще, в то время как регулярное выражение [1-2]*
будет соответствовать только последовательности 1 и 2. Мои скрипты на Bash и REGEX foo оба довольно слабые, и я регулярно сталкиваюсь с проблемами, связанными с этими различиями, и мне было любопытно, почему они различаются.
shell
regular-expression
wildcards
history
StrongBad
источник
источник
rm -- ^[^.].*\.txt$
вместоrm -- *.txt
?find . -regex ".*\.txt$" | xargs rm --
илиrename
для переименования файлов (этоsed
для имен файлов), имейте в виду, что некоторые системы имеют другоеrename
.^[^.].*\.txt$
должен был принять во внимание игнорирование файлов точек. Обратите внимание , что-regex
является GNU расширения, некоторые оболочки , как ksh93 или Zsh можно включить регэкспы в их комках (попробуйте, например:ksh93 -c 'echo ~(E:^[^.].*\.txt$)'
)Ответы:
bash
Первоначально был разработан в конце 80-х годов как частичный клонksh
с некоторыми интерактивными функциями из csh / tcsh.Источники шатания должны быть найдены в тех ранних оболочках, на которых они основаны.
ksh
сам по себе является продолжением оболочки Борна. Сама оболочка Bourne (впервые выпущенная в 1979 году в Unix V7) была чистой реализацией с нуля, но она не полностью отходила от оболочки Thompson (оболочка V1 -> V6) и включала функции оболочки Mashey.В частности, аргументы команды по-прежнему были разделены пробелами,
|
теперь они были новым оператором канала, но^
все еще поддерживались в качестве альтернативы (а также объясняют, почему вы этого[!a-z]
не делаете[^a-z]
),$1
были по-прежнему первым аргументом в сценарии, а обратная косая черта по-прежнему была escape-символом. , Поэтому многие операторы регулярных выражений (^\|$
) имеют особое значение в оболочке.Оболочка Томпсона опиралась на внешнюю утилиту для глобализации. Когда
sh
найден неупомянута*
,[
или?
S в команде, было бы запустить команду черезglob
.в итоге запустил glob как:
и glob заканчивает работу
rm
со списком файлов, соответствующих этому шаблону.будет работать
glob
как:*
Выше цитировались, установив 8 - бит на этом символе, предотвращаяglob
от лечения его в качестве шаблона.glob
затем удалит этот бит перед вызовомgrep
.Чтобы сделать эквивалент с регулярными выражениями, это было бы:
Или:
исключить dot-файлы.
Необходимость избегать операторов, поскольку они удваиваются как специальные символы оболочки, тот факт, что
.
в именах файлов часто используется оператор регулярного выражения, делает его не очень подходящим для сопоставления имен файлов и сложным для начинающего. В большинстве случаев все, что вам нужно, это подстановочные знаки, которые могут заменить один (?
) или любое число (*
) символов.Теперь в разные оболочки добавлены разные операторы сглаживания. В настоящее время глобусы ksh и zsh (и в некоторой степени,
bash -O extglob
которые реализуют подмножество глобусов ksh) функционально эквивалентны регулярным выражениям с синтаксисом, который менее громоздок для использования с именами файлов и текущим синтаксисом оболочки. Например, вzsh
(с расширением extendedglob) вы можете сделать:если вы хотите (маловероятно) сопоставить имена файлов, которые состоят из последовательностей, за
a
которыми следует.txt
. Проще, чемecho (^a*\.txt$)
(здесь использование фигурных скобок как способ изолировать операторы регулярных выражений от операторов оболочки, которые могли бы быть единственными способами, с которыми оболочки могли бы справиться)Для файлов mpg (без учета регистра), базовым именем которых является foo, bar или десятичное число от 1 до 20 ...
ksh93
теперь может также включать регулярные выражения (базовые, расширенные, perl-подобные или «расширенные») в свои глобусы (хотя они довольно глючные) и даже предоставляет инструмент для преобразования между глобальными и регулярными выражениями (printf %R
,printf %P
):в матч (не скрытый) TXT файлов с E Xtended регулярных выражений, к регистру I nsensitively.
источник
~(opt:pat)
ни для одной из опций с большой буквы. Может бытьprint -r -- ~(Ei).*\.txt$
. Помещение шаблона внутрь кажется полезным только для того, чтобы не включать и не выключать опцию для части шаблона. Как ни странно, вы можете смешивать и сочетать несколько языков шаблонов в одном глобусе.~(Ki)*.~(E)txt$
эквивалентно. (В конце концов, все просто преобразуется в регулярные выражения и передается внутреннему движку регулярных выражений libast).~(Ei:.*\.txt)
у меня работает даже с 15-летними версиями вроде ksh93 o +.~(E)x
и в~(E:x)
том , что последний якорь (матчи наx
только тогда , когда прежние матчи на все , что содержитx
), которые могут быть своего рода вопрос вы столкнулись с (использование~(-lr)~(E:x)
для удаления прикрепление,~(E-lr:x)
не будет делать). В любом случае, я согласен, что он довольно глючный, даже в последней версии.Регулярные языки были введены Клини в 1956 году. В оригинальной статье не было полной современной записи для регулярных выражений, но она ввела «звезду Клина», что
A*
означает «любое количество повторенийA
». В следующее десятилетие появилось несколько более или менее стандартных обозначений, в частности.
для произвольного символа и?
означающих, что предыдущий символ является необязательным.Глобальная нотация Bash происходит от
glob
команды, введенной в Unix v1 в 1971 году. В то время глобализация выполнялась отдельной программой; это было позже перемещено в раковину. Ранняяglob
команда?
должна означать «любой один символ» и*
«любую последовательность символов». Я не знаю, почему персонажи были выбраны;?
является довольно интуитивным, и,*
возможно, был вдохновлен тем, что в регулярных выражениях.Глобирование не предназначалось для того, чтобы быть таким же общим, как регулярные выражения, и регулярные выражения не были широко распространены в то время, поэтому не было необходимости объединять понятия. С самого начала были синтаксическая Несовместимостью с
?
,.
и это*
означают разные вещи в шаблонах имен файлов и в регулярных выражениях.Современные оболочки, такие как bash, расширяют шаблоны глобусов, но это была постепенная эволюция, поддерживающая обратную совместимость. Ksh88 (версия оболочки Korn 1988 года ) ввел расширенный синтаксис для шаблонов оболочки, который не мог быть тем же синтаксисом, что и обычные регулярные выражения, но сильно вдохновлялся им:
*(PATTERN)
означать любое количество повторенийPATTERN
,@(PATTERN1|PATTERN2)
означать «PATTERN1
илиPATTERN2
», и т.п.Современные версии bash (начиная с 2.02) поддерживают расширенные шаблоны ksh88, если вы выпустите их
shopt -s extglob
первым.источник
extglob
опция были представлены в bash 2.02 где-то в 1998 году. Zsh приобрелksh_glob
в серии 3.1 где-то в то же время. У Zsh есть много собственных расширений (некоторые требуютextended_glob
опции).bash
отличие отksh
extglob делает bash не POSIX-совместимым, потому что он не отключен в переменных. Вksh
,var='@(*)'; echo $var
расширяется до всех имен файлов в текущем каталоге, которые начинаются@(
и заканчиваются в)
соответствии с требованиями POSIX, в то время как вbash -O extglob
нем распространяются на все файлы. (тем не менее, можно подумать, что поведение bash здесь имеет больше смысла (и поведение ksh - довольно трудная задача, если вы хотите иметь шаблоны в переменных)). Из-за этого этот синтаксис glob очень неудобен (совместимость с POSIX / Bourne). Сравните с расширенными шарами zsh.Историческая причина: ДА. Ссылка:
http://en.wikipedia.org/wiki/Glob_(programming)#Origin
Просто чтобы продемонстрировать расхождение, вот хороший и простой пример:
a*
a
а затем все что угодно (a, ab, abca ...)a
(a, aa, aaa ...)Я бы с готовностью согласился, что это несоответствие в значении очень запутанно для новых пользователей.
Для новичков, возможно, легче понять глобпинг, но он также является менее мощной конструкцией.
источник