Регулярное выражение в find - OS X

С perl :

perl -lpe 'if (/\H+#/) {$word = $&} else {$_ = $word . $_}'

То есть, если мы найдем последовательность непустых символов ( \ H + ), за которым следует # в строке, мы используем это ( $ & - это то, что соответствует регулярному выражению) в качестве слова, которое нужно вставить в начало следующих строк. .

То же самое с awk :

awk '
  match($0, /[^[:blank:]]+#/) {
    word = substr($0, RSTART, RLENGTH)
    print
    next
  }
  {print word $0}'

То же самое с sed (с использованием пространства удержания для хранения слова ):

sed '
  /[^[:blank:]]\{1,\}#/ {
    h; # save the line in the hold space
    s//\
&\
/; # put newlines on each side of the matched word
    s/.*\n\(.*\)\n/\1/; # remove every thing but the word
    x; # swap hold and pattern space so that now the hold
       # space contains the word. And branch off:
    b
  }
  # for the other lines:
  G; # append the hold space to the pattern space
  s/\(.*\)\n\(.*\)/\2\1/; # move the word to the beginning'

Если вы хотите сопоставить только слова # , которые находятся в конце строки, замените # на # $ во всех трех приведенных выше командах.

1
03.05.2016, 20:13
2 ответа

-name принимает шаблоны подстановки, а не регексы и сопоставляет имя файла, а не его полный путь. Используйте -regex (или -iregex) для сопоставления с regexp, но помните, что он сопоставляет с полным путем. Здесь можно сделать так:

LC_ALL=C find -E . -iregex '.*s[0-9]{1,2}\.?e[0-9]{1,2}[^/]*\.mkv'

Здесь мы заменяем второй .* на [^/]*, то есть последовательность не/ символов, чтобы убедиться, что шаблон перед ним соответствует имени файла, а не компонентам каталога.

Установив локаль на C с помощью LC_ALL=C, мы убеждаемся, что . соответствует любому байту, а [^/] - любому байту, кроме /, так как в противном случае вы можете столкнуться с проблемами при использовании имен файлов или каталогов, закодированных в другом наборе символов, чем в вашей локали. Установка локали на C также гарантирует, что e будет соответствовать только e и Es на s и S) с -iregex.

Обратите внимание, что [\.] совпадает с обратной косой чертой или точкой. Для соответствия точке, это либо \. или [.]. Также x{1} то же самое, что x, поэтому я убрал {1} для упрощения.

Проверьте вашу страницу man для подробностей. Обратите внимание, что ни один из -E, -regex или -iregex не является стандартным.

Это можно упростить до

LC_ALL=C find -E . -iregex '.*s[0-9]{1,2}\.?e[0-9][^/]*\.mkv'

Так как вторая цифра, если она есть, также будет соответствовать [^/] в любом случае.

Стандартный эквивалент с использованием шаблонов подстановки будет выглядеть так:

LC_ALL=C find . -name '*[sS][0-9][0-9].[eE][0-9]*.mkv' \
             -o -name '*[sS][0-9].[eE][0-9]*.mkv' \
             -o -name '*[sS][0-9][0-9][eE][0-9]*.mkv' \
             -o -name '*[sS][0-9][eE][0-9]*.mkv'

шаблоны подстановки, в отличие от расширенных регулярных выражений, не имеют оператора чередования или эквивалента ? или {n,p}, поэтому нам нужно 4 шаблона, чтобы охватить все возможности.

Вы также можете использовать оболочку с рекурсивным блобингом и расширенными шаблонами подстановочных знаков, например zsh:

setopt extendedglob
ls -lrtd -- **/(#i)*s<->e<->*.mkv
  • **/ рекурсивный поиск
  • (#i) поиск без учета регистра
  • <-> любое десятичное число

Передаем ls -lrtd сюда, чтобы вывести список с деталями, отсортированный по времени последней модификации, хотя, конечно, вы можете использовать любую команду.

2
27.01.2020, 23:35

find dir -name просто поддерживает символы glob имен файлов оболочки, как описано в man fnmatch.

Некоторые реализации find поддерживают нестандартные расширения для регулярных выражений. Проверьте man-страницу find.

0
27.01.2020, 23:35

Теги

Похожие вопросы