Estoy usando ffmpeg para obtener la metainformación de un clip de audio. Pero no puedo entenderlo.
$ ffmpeg -i 01-Daemon.mp3 |grep -i Duration
FFmpeg version SVN-r15261, Copyright (c) 2000-2008 Fabrice Bellard, et al.
configuration: --prefix=/usr --bindir=/usr/bin
--datadir=/usr/share/ffmpeg --incdir=/usr/include/ffmpeg --libdir=/usr/lib
--mandir=/usr/share/man --arch=i386 --extra-cflags=-O2
...
Verifiqué, esta salida de ffmpeg está dirigida a stderr.
$ ffmpeg -i 01-Daemon.mp3 2> /dev/null
Así que creo que grep no puede leer la secuencia de errores para detectar líneas coincidentes. ¿Cómo podemos habilitar grep para leer la secuencia de error?
Usando el enlace nixCraft , redirigí el flujo de error estándar al flujo de salida estándar, luego grep funcionó.
$ ffmpeg -i 01-Daemon.mp3 2>&1 | grep -i Duration
Duration: 01:15:12.33, start: 0.000000, bitrate: 64 kb/s
Pero, ¿qué pasa si no queremos redirigir stderr a stdout?
grep
io-redirection
ffmpeg
Andrew-Dufresne
fuente
fuente
grep
eso solo puede funcionar en stdout (aunque no puedo encontrar la fuente canónica para respaldar eso), lo que significa que cualquier flujo debe convertirse primero en stdout.grep
solo puede funcionar con stdin. Es la tubería creada por el shell que conecta el stdin de grep con el stdout del otro comando. Y el shell solo puede conectar un stdout a un stdin.Respuestas:
Si está utilizando
bash
por qué no emplear tuberías anónimas, en esencia, abreviatura de lo que dijo phunehehe:ffmpeg -i 01-Daemon.mp3 2> >(grep -i Duration)
fuente
cp
cp -r dir* to 2> >(grep -v "svn")
>&2
, por ejemplo,command 2> >(grep something >&2)
2>
redirige stderr a archivo, lo entiendo. Esto se lee del archivo>(grep -i Duration)
. Pero el archivo nunca se almacena? ¿Cómo se llama esta técnica para poder leer más al respecto?Ninguno de los shells habituales (incluso zsh) permite tuberías que no sean stdout a stdin. Pero todos los shells de estilo Bourne admiten la reasignación de descriptores de archivo (como en
1>&2
). Por lo tanto, puede desviar temporalmente stdout a fd 3 y stderr a stdout, y luego colocar fd 3 nuevamente en stdout. Sistuff
produce alguna salida en stdout y otra salida en stderr, y desea aplicarfilter
en la salida de error dejando intacta la salida estándar, puede usarla{ stuff 2>&1 1>&3 | filter 1>&2; } 3>&1
.fuente
pipestatus
ayudaríaset -o pipefail
puede ser útil aquí, dependiendo de lo que desee hacer con el estado del error. (Por ejemplo, si haset -e
activado para fallar en algún error, probablementeset -o pipefail
también desee ).set -e
activado para fallar en cualquier error.rc
carcasa permite tuberías stderr. Vea mi respuesta a continuación.Esto es similar al "truco del archivo temporal" de phunehehe, pero en su lugar utiliza una canalización con nombre, lo que le permite obtener resultados un poco más cercanos a cuando salen, lo que puede ser útil para comandos de ejecución prolongada:
En esta construcción, stderr se dirigirá a la tubería llamada "mypipe". Como
grep
se ha llamado con un argumento de archivo, no buscará en STDIN su entrada. Desafortunadamente, aún tendrá que limpiar esa tubería con nombre una vez que haya terminado.Si está utilizando Bash 4, hay una sintaxis de acceso directo para
command1 2>&1 | command2
, que escommand1 |& command2
. Sin embargo, creo que esto es puramente un acceso directo de sintaxis, todavía está redirigiendo STDERR a STDOUT.fuente
|&
sintaxis es perfecta para limpiar rastros hinchados de pila de Ruby stderr. Finalmente puedo agarrarlos sin demasiados problemas.Las respuestas de Gilles y Stefan Lasiewski son buenas, pero de esta manera es más simple:
Supongo que no quieres
ffmpeg's
imprimir stdout.Cómo funciona:
fuente
Vea a continuación el script utilizado en estas pruebas.
Grep solo puede operar en stdin, por lo tanto, debe convertir la secuencia stderr en una forma que Grep pueda analizar.
Normalmente, stdout y stderr se imprimen en su pantalla:
Para ocultar stdout, pero aún imprimir stderr, haga esto:
¡Pero grep no funcionará en stderr! Es de esperar que el siguiente comando suprima las líneas que contienen 'err', pero no lo hace.
Aquí está la solución.
La siguiente sintaxis de Bash ocultará la salida a stdout, pero seguirá mostrando stderr. Primero canalizamos stdout a / dev / null, luego convertimos stderr a stdout, porque las tuberías Unix solo funcionarán en stdout. Todavía puedes grep el texto.
(Tenga en cuenta que el comando anterior es diferente a continuación
./command >/dev/null 2>&1
, que es un comando muy común).Aquí está la secuencia de comandos utilizada para las pruebas. Esto imprime una línea en stdout y una línea en stderr:
fuente
./stdout-stderr.sh 2>&1 >/dev/null | grep err
.Cuando canaliza la salida de un comando a otro (usando
|
), solo está redirigiendo la salida estándar. Entonces eso debería explicar por quéno emite lo que quería (sin embargo, funciona).
Si no desea redirigir la salida de error a la salida estándar, puede redirigir la salida de error a un archivo, luego grep más tarde
fuente
it does work, though
¿Quieres decir que está funcionando en tu máquina? En segundo lugar, como señaló con el uso de tubería, solo podemos redirigir stdout. Estoy interesado en algún comando o función bash que me permita redirigir stderr. (pero no el truco del archivo temporal)Puede intercambiar las transmisiones. Esto le permitiría
grep
obtener el flujo de error estándar original mientras obtiene la salida que originalmente fue a la salida estándar en el terminal:Esto funciona creando primero un nuevo descriptor de archivo (3) abierto para la salida y configurándolo en la secuencia de error estándar (
3>&2
). Luego redirigimos el error estándar a la salida estándar (2>&1
). Finalmente, la salida estándar se redirige al error estándar original y se cierra el nuevo descriptor de archivo (1>&3-
).En tu caso:
Probándolo:
fuente
Me gusta usar el
rc
shell en este caso.Primero instale el paquete (es inferior a 1 MB).
Este es un ejemplo de cómo descartaría
stdout
y canalizaríastderr
greprc
:find /proc/ >[1] /dev/null |[2] grep task
Puedes hacerlo sin salir de Bash:
rc -c 'find /proc/ >[1] /dev/null |[2] grep task'
Como habrás notado, la sintaxis es sencilla, lo que hace que esta sea mi solución preferida.
Puede especificar qué descriptor de archivo desea canalizar entre paréntesis, justo después del carácter de canalización.
Los descriptores de archivo estándar están numerados como tales:
fuente
Una variación en el ejemplo de subproceso bash:
haga eco de dos líneas para stderr y tee stderr a un archivo, coloque el tee y la tubería de nuevo a stdout
stdout:
some.load.errors (por ejemplo, stderr):
fuente
prueba este comando
ceva -> solo un nombre de variable (inglés = algo)
fuente
/tmp/$ceva
, mejor que ensuciar el directorio actual con archivos temporales, y está asumiendo que el directorio actual es editable.