Вы можете поменять потоки местами. Это позволит вам grep
оригинальный поток стандартной ошибки, получая при этом вывод, который изначально шел на стандартный вывод в терминале:
somecommand 3>&2 2>&1 1>&3- | grep 'pattern'
Это работает путем создания нового файлового дескриптора (3), открытого для вывода, и установки его на поток стандартной ошибки (3>&2
). Затем мы перенаправляем стандартную ошибку на стандартный вывод (2>&1
). Наконец, стандартный вывод перенаправляется на исходную стандартную ошибку, а новый дескриптор файла закрывается (1>&3-
).
В вашем случае:
ffmpeg -i 01-Daemon.mp3 3>&2 2>&1 1>&3- | grep -i Duration
Проверяем:
$ ( echo "error" >&2; echo "output" ) 3>&2 2>&1 1>&3- | grep "error"
output
error
$ ( echo "error" >&2; echo "output" ) 3>&2 2>&1 1>&3- | grep -v "error"
output
Scroll вплоть до « Генерация имени файла » и включите либо extended_glob
(что должно быть по умолчанию, но не для обратной совместимости), либо ksh_glob
. И расширенные глобусы zsh, и ksh обладают всеми возможностями регулярных выражений.
ERE syntax ksh glob zsh extended glob
(foo)* *(foo) (foo)#
(foo)+ +(foo) (foo)##
(foo)? ?(foo) (|foo)
(foo|bar) @(foo|bar) (foo|bar)
Имейте в виду, что большинство инструментов, использующих регулярные выражения, используют их как шаблоны поиска , которые должны соответствовать подстроке, но глобусы всегда используются как шаблоны, которые должны соответствовать всей строке. Например, foofoobar
не соответствует zsh glob (foo) ##
, поскольку после foofoo
остается некоторый текст.
В Zsh есть дополнительные операторы, которые не расширяют выразительные возможности, но упрощают написание некоторых выражений. Операторы ^
и ~
( extended_glob
) и ! (…)
( ksh_glob
) обеспечивают отрицание, например ^ foo
или ! (Foo)
соответствует чему угодно, кроме foo
, что в синтаксисе регулярного выражения требует громоздкого | [^ f]. * | F [ ^ o]. * | fo [^ o]. *
. Оператор <… -…>
(специфично для zsh, не требует extended_glob
) соответствует любому целому числу (в десятичной системе счисления) в диапазоне, например <3-11>
соответствует 3
и 10
, но не 30
или 1
.
Итак, исключая такие проблемы, как непечатаемые символы, ls | grep -e "ABC [0-9] \ +"
можно записать такими способами, как
print -lr -- *ABC[0-9]##*(N) # requires extended_glob
print -lr -- *ABC+([0-9])*(N) # requires ksh_glob
print -lr -- *ABC+<->(N)
. Но поскольку «одна или несколько цифр, затем что угодно» эквивалентно «цифра, затем что угодно», это также может быть написано
print -lr -- *ABC[0-9]*(N)
При включенном extendedglob
:
$ setopt extendedglob
$ print -rl -- perl[[:digit:]]##
perl5
или при включенном kshglob
и отключенном bareglobqual
:
$ setopt kshglob
$ unsetopt bareglobqual
$ print -rl -- perl+([[:digit:]])
perl5
Обратите внимание, что использование [: digit:]
для сопоставления всех рассматриваемых цифр в текущей локали. Если вы хотите сопоставить только 0
- 9
, установите LC_ALL = C
или используйте буквально [0123456789]
.
Вы можете указать количество совпадений, например, регулярное выражение {n, m}
, используя (# cN, M)
флаг подстановки в любом месте, где #
и ##
могут использоваться операторы, кроме (* /) #
и (* /) ##
:
$ print -rl -- perl[[:digit:]](#c1)
perl5
$ print -rl -- perl[[:digit:]](#c2)
zsh: no matches found: perl[[:digit:]](#c2)
Да, используйте ##
, чтобы сопоставить одно или несколько вхождений [0-9]
, например:
ABC[0-9]##
Для этого необходимо установить extendedglob
, что по умолчанию. Если не установлено, сначала установите его:
setopt extendedglob
Пример:
% print -l ABC*
ABC
ABC75475
ABC8
ABC90
% print -l ABC[0-9]##
ABC75475
ABC8
ABC90