J'utilise actuellement la configuration suivante pour rediriger la sortie de plusieurs commandes:
echo "Some normal commands"
(
echo "Error: something happened"
echo "Warning: this incident will be logged"
) >> logfile
echo "More normal commands"
C'est assez utile, et cela fonctionne également avec les tuyaux.
Est-ce la meilleure façon de procéder? Y a-t-il une alternative à considérer?
bash
shell-script
io-redirection
wchargin
la source
la source
:)
Réponses:
L'alternative consiste à utiliser des accolades au lieu de parenthèses. Cette modification exécute les commandes dans le shell actuel , pas dans un sous - shell
réf: https://www.gnu.org/software/bash/manual/bashref.html#Command-Grouping
Ceci est particulièrement pertinent lorsque vous modifiez des variables à l'intérieur du groupe:
la source
{ }
mais pas( )
.)(echo msg1; echo msg2)
- mais, avec des accolades, il doit être{ echo msg1; echo msg2;}
, avec un espace après le{
et un point-virgule (;
) ou une esperluette (&
) avant le}
.La réponse de Glenn est bonne - la distinction entre
( ... )
et{ ... }
est importante.Une stratégie que j'utilise souvent pour la sortie d'erreur comme ce qui est dans votre question est la
tee
commande. Vous pourriez faire quelque chose comme ça:La
tee
commande enverra la sortie à deux endroits;-a
l'option "ajoute" la sortie au fichier nommé, et la commande passera également l'entrée à stdout. La>&2
fin de la ligne redirige la sortietee
standard de stdout vers stderr, qui peut être traitée différemment (c'est-à-dire dans une tâche cron).Une autre astuce que j'utilise souvent dans les scripts shell est de changer le comportement du débogage ou de la sortie détaillée selon que le script s'exécute sur un terminal ou dispose d'une
-v
option. Par exemple:Les scripts peuvent commencer par quelque chose de générique comme celui-ci en haut, avec des sorties verbeuses et de débogage dispersées tout au long du script. C'est juste une façon de le faire - il y en a beaucoup, et différentes personnes auront toutes leur propre façon de gérer ce genre de choses, surtout si elles existent depuis un certain temps. :)
Une autre option consiste à gérer votre sortie avec un "gestionnaire" - une fonction shell qui peut faire des choses plus intelligentes. Par exemple:
(Notez que
${var^^}
c'est uniquement bash.)Cela crée une fonction shell qui peut utiliser les
syslog
fonctions de votre système (avec lalogger
commande) to send things to system logs. The
logme () `la fonction peut être utilisée soit avec des options qui génèrent des lignes de données de journal uniques, soit avec plusieurs lignes d'entrée qui sont traitées sur stdin. Jouez avec si elle semble attrayant.Notez que ceci est un exemple et ne devrait probablement pas être copié mot pour mot à moins que vous ne le compreniez et sachiez qu'il fait exactement ce dont vous avez besoin. Une meilleure idée est de prendre les concepts ici et de les implémenter vous-même dans vos propres scripts.
la source
function log () { cat >> $logfile }
, qui est essentiellement une version plus simple de votrelogme
.ts(1)
; utilisation:{ printf '%s\n' "Warning text"; printf '%s\n' "This event will be logged"; } | ts '[%Y-%m-%d %T]' | tee -a "$logfile" >&2
.ts(1)
n'est pas installé sur les systèmes que j'utilise - FreeBSD, OSX et une vieille boîte Ubuntu. Pouvez-vous nous dire ce qui le fournit?sponge(1)
(écrire dans le fichier uniquement après la fermeture de stdin, vous pouvez donc vous passer desomething < foo | sponge foo
clobberfoo
par redirection), etvipe(1)
(insérer un éditeur de texte dans un tuyau).La manière la plus appropriée de le faire est
{ command; }
plutôt que(command)
. La raison en est que lorsque les commandes sont regroupées avec()
un sous-shell est ouvert pour exécuter ces commandes et donc les variables qui sont initialisées pendant ce bloc ne seront pas disponibles pour les autres sections du script.Au lieu de cela, lorsque nous utilisons
{}
pour le regroupement de commandes, les commandes sont exécutées dans le même shell et donc les variables seront disponibles pour d'autres sections du script.Ici, lorsque cette section est exécutée, la
$var
variable conserve sa valeur, ce qui n'est pas le cas dans l'autre cas.la source
{ command; }
.