Envoyer stdout et stderr vers un fichier, un syslog et un terminal

8

Pour certaines machines cloud que je lance, j'essaie de me connecter à un fichier spécifique, syslog et le terminal / console.

En haut de mes scripts de configuration de machine / cloud-init, j'ai les éléments suivants:

#!/bin/bash
exec &> >(tee "/tmp/box-setup.log" | logger -t box-setup)
apt-get install -y some-package

Cela fonctionne très bien pour envoyer la sortie vers un fichier et un syslog, mais cela ne dirige pas vers la sortie vers le terminal.

D'une manière générale, ne pas avoir de sortie de terminal n'est pas un problème énorme, sauf lorsque je débogue à partir d'une console distante. Lorsque cela se produit, je suis complètement aveugle car la console est vide pendant l'exécution du script bash.

Existe-t-il un moyen simple d'utiliser la bashredirection ou autre pour diriger simultanément toutes les sorties (sortie standard avec erreur standard) vers un fichier, un journal système et le terminal?

J'utilise Ubuntu 16.04.

Jonathan Oliver
la source

Réponses:

8

Ajoutez une substitution de processus imbriquée et une autre teecomme:

exec &> >(tee >(tee "/tmp/box-setup.log" | logger -t box-setup))

Le premier teede la substitution de processus principale envoie STDOUT / STDERR au terminal et également à la substitution de processus imbriquée, l' teeintérieur qui enregistre le contenu dans le fichier /tmp/box-setup.loget le canal est également utilisé pour envoyer la sortie au loggerSTDIN de.

heemayl
la source
Je suis confus à propos de plusieurs invocations de tee, cela va se bifurquer vers n streams, cela ne devrait-il pas être équivalent? exec &> >(tee /tmp/box-setup.log >(logger -t box-setup))
ThorSummoner
3

Je suis complètement aveugle car la console est vide pendant l'exécution du script bash.

Vous voudrez peut-être résoudre ce problème d'une manière différente: exécutez votre script bash en arrière-plan, puis exécutez less /tmp/box-setup.loget appuyez sur F pour continuer à mettre à jour l'écran lorsque des lignes sont ajoutées au fichier qu'il regarde (comme tail -f).

Si l'exécution du script en arrière-plan pose problème, utilisez tmuxou screenpour multiplexer plusieurs sessions sur une connexion ssh. Utilisez la même lesscommande dans un autre shell.


Le problème d'origine:

teepeut copier vers plusieurs destinations. Faites de l'un d'eux le terminal, en utilisant le /dev/ttyfichier spécial. Je pense que cela fait toujours référence au contrôle du processus actuel. Ou probablement mieux, /dev/stderrpuisque teele stderr de est toujours connecté au stderr du shell. (Cela vous permet de désactiver le script avec &> / dev / null).

exec &> >(tee /dev/stderr "/tmp/box-setup.log" | logger -t box-setup)

BTW, c'est équivalent mais plus efficace que (tee /dev/stderr | tee "/tmp/box-setup.log" | logger ...).

Il serait possible d'utiliser un clonage de descripteur de fichier pour donner teela sortie standard du script original, plutôt que la sortie stderr.

Peter Cordes
la source
1

Ajoutez simplement /dev/stderr(votre choix) comme sortie à tee.

exec &> >(tee /dev/stderr "/tmp/box-setup.log" | logger -t box-setup)

La sortie standard et l'erreur standard seront fusionnées. Il n'y a aucun moyen de les séparer si vous souhaitez conserver leur ordre, ce qui est généralement souhaitable. Peu importe qu'ils se rendent tous les deux au même endroit (par exemple, le terminal) de toute façon.

Gilles 'SO- arrête d'être méchant'
la source
teeLa sortie standard est le tuyau vers l'enregistreur, pas le terminal. C'est stderrà ce moment-là que se trouve le terminal, basé sur le exec &> >(tee /dev/stderr > /dev/null)fonctionnement comme prévu dans un shell interactif. stderrsemble être une meilleure idée que mon /dev/ttyidée, car elle vous permet de fermer facilement le script avec une redirection si vous le souhaitez.
Peter Cordes