Регулярное выражение в команде оболочки bash работает отдельно, а не как часть более крупного регулярного выражения

#regex #bash

#регулярное выражение #bash

Вопрос:

У меня есть короткий скрипт для перемещения файлов журнала apache, которые старше x дней, в хранилище. Регулярное выражение фиксирует имя файла jk.shm.some_number в каталоге mod_jk, что является нежелательным поведением (не большая проблема, поскольку я использую флаг mtime с подушкой на несколько дней, чтобы избежать случайного удаления текущих активных файлов. Вероятно, причина, по которой я до сих пор не видел, чтобы эта проблема всплывала). Все регулярное выражение: '[error,access,error_log,access_log,mod_jk.log]*.[0-9]*' Которое, я думаю, работает только из-за глупой удачи. Я также попытался изолировать часть mod_jk для запуска самостоятельно 'mod_jk.log.[0-9]*' , и она работает так, как ожидалось (с или без перед .). Как только я включаю его в скобки, он выбирает файл jk.shm.some_number — я предполагаю, потому что он соответствует диапазону символов в скобках. Я пытаюсь решить это с помощью RegexBuddy, но я подумал, что один из умных людей мог бы указать на мои ошибки и помочь мне на правильном пути.

Это текущая строка, которая «работает» с удаленным флагом -mtime:

 find -name '[error,access,error_log,access_log,mod_jk.log]*.[0-9]*' -type f
  

Комментарии:

1. Лучше всего было бы предоставить несколько строк, которые должны быть сопоставлены.

2. ошибка.11111111111, access.11111111, error_log.1111111111, access_log.1111111, mod_jk.log.111111111. В основном имена файлов файлов журнала в каталоге и подкаталогах файлов журнала apache, которые, как я думал, я объяснил выше.

3. Я предполагаю, что вы вообще не используете регулярное выражение, а глобальный шаблон. Если вы пытаетесь сделать что-то подобное mv {access,error,access_log,error_log,mod_jk.log}.[0-9]* dir , то это расширенный глобальный шаблон, а не регулярное выражение, и они должны быть фигурными скобками.

4. @tripleee Я думаю, что вы с Крисом приближаете меня, я заметил проблему [], когда начал разбирать эту проблему.

5. Пожалуйста, опубликуйте команду или код, в котором вы пытаетесь заставить это работать, вы заставляете нас гадать.

Ответ №1:

Если у вас find есть -regex опция, вы можете использовать это; в противном случае вам придется разделить это на отдельные глобальные шаблоны.

 find -type f -name 'error.[0-9]*' -o -name 'access.[0-9]*' -o -name 'error_log.[0-9]*' -o -name 'access_log.[0-9]*' -o -name 'mod_jk.log.[0-9]*' 
  

Обратите внимание, что в шаблонах glob * это просто подстановочный знак в стиле DOS, а не оператор повторения регулярных выражений. Если у вас есть find -regex , у вас больше контроля над сопоставлением.

 find -type f -regex '.*((error|access)(_log)?|mod_jk.log).[0-9] '
  

Как в регулярных выражениях, так и [ab|cd] в глобусе соответствует только одному символу из набора, перечисленного внутри скобок; символ канала просто представляет себя в этом контексте.

Ответ №2:

* s соответствует нулю или более символов, так что на самом деле это регулярное выражение будет соответствовать любому *.* имя файла. Похоже, вы захотите изменить свой * s на s, что приведет к хотя бы одному совпадению предыдущего выражения.

Комментарии:

1. Я думал, что в этом случае [элементы] * должны соответствовать любому из элементов в скобках, а не выступать в качестве подстановочного знака. [0-9]* должно соответствовать любому числу, следующему за разделителем расширений файлов ‘.’. Если я использую , ничего не сопоставляется.

Ответ №3:

Я думаю, вы улучшили

 (error|access|error_log|access_log|mod_jk.log).[0-9] 
  

Ваше регулярное выражение соответствует всем именам, содержащим только буквы в ваших первых квадратных скобках и «,», и, возможно, некоторые цифры после точки. Только точка тоже была бы хороша.

Если вы хотите предоставить альтернативы, используйте круглые скобки с каналом в качестве разделителя. Знаете ли вы, сколько цифр у вас есть (по крайней мере) после точки?

Комментарии:

1. Для меня это работает: TEST=access_log.1111111; EXPR="(error|access|error_log|access_log|mod_jk.log).[0-9] "; [ $TEST =~ $EXPR ]; echo $? — Как вы выполняете регулярное выражение? Я думаю, что это выражение использует «расширенную» нотацию, grep потребуется дополнительный флаг, если я не ошибаюсь.

2. Я использую его как часть find: find -name ‘regex_here’ -введите f -mtime … Я не знаю точной длины каждого расширения, но [0-9] *, похоже, пока работает, насколько эта часть поиска идет.

Ответ №4:

ваш шаблон:

 '[error,access,error_log,access_log,mod_jk.log]*.[0-9]*'
  

делает не то, что вы думаете. Даже в качестве регулярного выражения это было бы некорректно, но bash использует глобализацию.
[] соответствует одному символу, но не полным словам, как вы пытаетесь,
* соответствует не или нескольким вхождениям любого символа, но не последовательности символов в диапазоне от 0 до 9, как я полагаю, вы пытаетесь сопоставить.

Сначала включите расширенную глобализацию с помощью:

 shopt -s extglob
  

затем используйте:

  (pattern1|pattern2|..) for alternate patterns.
  

и

  ([0-9]|[0-9][0-9]|..)
  

HTH Крис

Комментарии:

1. Спасибо за ответ, вы помогли мне начать правильный путь. Проблема заключалась в том, что я использовал find, а не параметр -regex . Я ценю помощь.