miércoles, 7 de octubre de 2009

Redirecciones en Bash

Todo el mundo ha visto la redireccion de comandos bash, pero bash también te permite definir redirecciones cuando defines funciones. Eso causa la redirecciones para ser evaluadas/ejecutadas cuando se llama a la función. Esta característica en realidad no te da ninguna característica nueva, es solo otra forma de expresar las características existentes.

La sintaxis para esto es simple, simplemente agrega la redireccion al final de la definición de la función:

function testy()
{
...
} <> testy.out 2> testy.err

Ahora cada vez que se llama a la función testy su entrada vendrá de testy.in y su salida se ira a testy.out y cualquier error a testy.err

Ya que que la redireccion es evaluada cuando la función es llamada la redireccion puede usar variables y las variables también pueden evaluadas cuando la función es llamada. Entonces podrías hacer algo así:

#!/bin/bash

function testy()
{
echo testy westy
} >$out

out=jj1
testy
out=jj2
testy

Esto causara que la salida de la función vaya a diferentes archivos con cada llamada. La primera salida de la llamada ira a jj1 y la segunda a jj2:


$ bash j.sh; more jj?
::::::::::::::
jj1
::::::::::::::
testy westy
::::::::::::::
jj2
::::::::::::::
testy westy

Como ya se mencionó, esto realmente no es una nueva característica, puedes lograr lo mismo de esta forma:

#!/bin/bash

function testy()
{
echo testy westy
}

testy >jj1
testy >jj2

Un posible uso para esta característica podría ser el poner todo el código dentro de una función principal y luego redireccionar los errores de tal forma que te aseguras de que siempre sean capturados:

#!/bin/bash

log=kk
function error()
{
echo "$*" >&2
}
function testy()
{
error testy westy
}

function testy2()
{
error testy2 westy2
}

function main()
{
testy
testy2
} 2>$log

main

Ejecutándolo producirá esto:

$ bash k.sh ;cat kk
testy westy
testy2 westy2

Ya que bash también permite redirecciones para ser incluidas en bloques/listas {...} que podrías lograr lo mismo haciendo lo siguiente:

#!/bin/bash

log=mm
function error()
{
echo "$*" >&2
}
function testy()
{
error testy westy
}

function testy2()
{
error testy2 westy2
}

{
testy
testy2
} 2>$log

También puedes usar redirecciones en bloques/listas (...) pero esta causa que el comando sea ejecutado en un sub-shell, el cual no esta necesariamente aquí y el cual puede causar problemas ya que sub-shell es un proceso diferente.

Si te preguntas si puedes sobre escribir la redireccion en la llamada actual, la respuesta es no. Si intentas sobreescribirlas todo lo que pasara es que la redireccion esta ejecutada/evaluada primero luego las redirecciones en la definición de la función las reemplazara. Por ejemplo, revisa lo siguiente:

#!/bin/bash

function testy()
{
echo testy westy
} >nn1

testy >nn2

El archivo de salida especificada en la llamada (nn2) sera creada pero nada se escribirá en el.

No hay comentarios: