Actualmente uso la siguiente configuración para redirigir la salida de múltiples comandos:
echo "Some normal commands"
(
echo "Error: something happened"
echo "Warning: this incident will be logged"
) >> logfile
echo "More normal commands"
Esto es bastante útil, y también funciona con tuberías.
¿Es ésta la mejor manera de hacer ésto? ¿Hay alguna alternativa que deba considerar?
bash
shell-script
io-redirection
wchargin
fuente
fuente

:)Respuestas:
La alternativa es usar llaves en lugar de paréntesis. Este cambio ejecuta los comandos en el shell actual , no en un subshell
ref: https://www.gnu.org/software/bash/manual/bashref.html#Command-Grouping
Esto es particularmente relevante cuando está modificando variables dentro del grupo:
fuente
{ }pero no( ).)(echo msg1; echo msg2)- pero, con llaves, tiene que ser{ echo msg1; echo msg2;}, con un espacio después del{y un punto y coma (;) o un signo (&) antes del}.La respuesta de Glenn es buena: la distinción entre
( ... )y{ ... }es importante.Una estrategia que uso a menudo para la salida de errores, como lo que hay en su pregunta, es el
teecomando. Podrías hacer algo como esto:El
teecomando enviará la salida a dos lugares;-ala opción "agrega" salida al archivo nombrado, y el comando también pasará la entrada a stdout. El>&2final de la línea redirigeteeel stdout de stdout a stderr, que puede manejarse de manera diferente (es decir, en un trabajo cron).Otro consejo que uso a menudo en los scripts de shell es cambiar el comportamiento de la depuración o la salida detallada en función de si el script se ejecuta en un terminal o tiene una
-vopción provista. Por ejemplo:Las secuencias de comandos pueden comenzar con algo genérico como este en la parte superior, con resultados detallados y de depuración esparcidos por toda la secuencia de comandos. Es solo una forma de hacerlo: hay muchas, y diferentes personas tendrán su propia manera de manejar estas cosas, especialmente si han estado alrededor por un tiempo. :)
Una opción más es manejar su salida con un "controlador", una función de shell que puede hacer cosas más inteligentes. Por ejemplo:
(Tenga en cuenta que solo
${var^^}es bash).Esto crea una función de shell que puede usar las
syslogfunciones de su sistema (con la función deloggercomando) to send things to system logs. Thelogme () `puede usarse con opciones que generan líneas individuales de datos de registro o con múltiples líneas de entrada que se procesan en stdin. Juegue con ella si Parece atractivoTenga en cuenta que este es un ejemplo y probablemente no debería copiarse literalmente a menos que lo entienda y sepa que hace exactamente lo que necesita. Una mejor idea es tomar los conceptos aquí e implementarlos usted mismo en sus propios scripts.
fuente
function log () { cat >> $logfile }, que es básicamente una versión más simple de tulogme.ts(1); Uso:{ printf '%s\n' "Warning text"; printf '%s\n' "This event will be logged"; } | ts '[%Y-%m-%d %T]' | tee -a "$logfile" >&2.ts(1)no está instalado en los sistemas que uso: FreeBSD, OSX y una antigua caja de Ubuntu. ¿Puedes decirnos qué lo proporciona?sponge(1)(escribir en el archivo solo después de cerrar stdin, por lo que puedesomething < foo | sponge fooprescindir de clobberingfoopor redireccionamiento) evipe(1)(insertar un editor de texto en una tubería).La forma más apropiada de hacerlo es con
{ command; }más que con(command). La razón es que cuando los comandos se agrupan con()una subshell se abre para ejecutar esos comandos y, por lo tanto, las variables que se inicializan durante ese bloque no estarán disponibles para otras secciones del script.En cambio, cuando usamos
{}para la agrupación de comandos, los comandos se ejecutan dentro del mismo shell y, por lo tanto, las variables estarán disponibles para otras secciones del script.Aquí, cuando se ejecuta esta sección, la
$varvariable conserva su valor, donde, como en el otro caso, no lo hará.fuente
{ command; }.