С 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'
Если вы хотите сопоставить только слова #
, которые находятся в конце строки, замените #
на # $
во всех трех приведенных выше командах.
-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
и E
(и s
на 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
сюда, чтобы вывести список с деталями, отсортированный по времени последней модификации, хотя, конечно, вы можете использовать любую команду.
find dir -name
просто поддерживает символы glob имен файлов оболочки, как описано в man fnmatch
.
Некоторые реализации find поддерживают нестандартные расширения для регулярных выражений. Проверьте man-страницу find
.