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
tee
comando. Podrías hacer algo como esto:El
tee
comando enviará la salida a dos lugares;-a
la opción "agrega" salida al archivo nombrado, y el comando también pasará la entrada a stdout. El>&2
final de la línea redirigetee
el 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
-v
opció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
syslog
funciones de su sistema (con la función delogger
comando) to send things to system logs. The
logme () `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 foo
prescindir de clobberingfoo
por 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
$var
variable conserva su valor, donde, como en el otro caso, no lo hará.fuente
{ command; }
.