Retourner aux forums || Retourner au forum Programmation.shell
Programmation.shell : Redirection de scripts
Posté par Valdenaire Denis (page perso, ) le 03 août 2004petite question sur la redirection de script :
j'aimerai savoir (la cible c'est en bash, mais si en vous connaissez qui marche sous d'autres shells, pourquoi pas ?) comment faire une commande en début de mes scripts qui :
- envoie la sortie standard vers std_out.log
- envoie la sortie erreur (et toutes les autres, au cas ou) vers std_err.log
- si le terminal est interactif, affiche aussi à l'écran les deux sorties, sinon, n'affiche rien. (dans le cas des taches cron, par exemple)
les noms des fichiers sont juste pour l'exemple, bien sur. En fait, ils seraient remis à zero au debut de chaque script (avec un avertissement) ou nommés avec une date, bref, peu importe.
bon, pour l'instant je me bats avec exec, qui donne des résultats mitigés. Par exemple,
if ["${PS1}" ] ; then
exec 2> err.log > out.log
else
???
fi
fait ce qu'il faut. Mais reste le problème de la redirection en même temps vers le terminal et deux fichiers. J'ai essayé des douzaines de combinaisons, d'abord en lisant le manuel, puis un peu au hasard, (sait-on jamais :) mais je n'ai pas trouvé la solution...
Si quelqu'un a une idée...
Par contre, je signale un bon guide, Advanced Bash-Scripting Guide, sur TLDP,
http://www.tldp.org/LDP/abs/html/(...)
PS: j'ai beau visualiser, le caractère de redirection ne s'affiche pas très bien. pour info le " & gt ; " signifie superieur, pour ceusses qu'auraient du mal :)
> Lire le message (13 commentaires, moyenne: 1,4).
Take a cup of tee
Bonjour,
Le programme que tu recherches s'appelle tee. Pour rediriger la sortie d'un programme tout en l'affichant :
echo toto | tee /tmp/log
Par contre pour rediriger la sortie d'erreur vers autre chose ... j'ai pas trop d'idée.
Bonne chance !
-
[^]Re: Take a cup of tee
Posté par totof2000 () le 03/08/2004 à 13:18. (lien). Évalué à 1.Ci dessous un exemple en ksh sous aix (mais qui doit pouvoir s'adapter sous linux)
Il faut juste verifier que la commande who -m te retourne ceci (le deuxieme champ est interessant):
totof2000 pts/4 02 ao{ 15:24
#!/bin/ksh
# Identification du pseudo-terminal de sortie
SORTIE=/dev/$( who -m |awk '{ print $2}')
echo $SORTIE
# Commande:
(ls - toto | tee titi.log>$SORTIE)2>&1 | tee error.log
Tu mets tout ca dans un script test1.ksh (ou test1.sh, peu importe).
A l'exécution:
$ksh test1.ksh
/dev/pts/4
ls : 0653-341 Le fichier - n'existe pas.
ls : 0653-341 Le fichier toto n'existe pas.
$more titi.log
$more error.log
ls : 0653-341 Le fichier - n'existe pas.
ls : 0653-341 Le fichier toto n'existe pas.
$
$touch toto
$ksh test1.ksh
/dev/pts/4
toto
ls : 0653-341 Le fichier - n'existe pas.
$more titi.log
toto
$more error.log
ls : 0653-341 Le fichier - n'existe pas.
Normalement, en cron, le pseudo-terminal devrait être /dev/null (a verifier).
-
[^]Re: Take a cup of tee
Posté par Valdenaire Denis (page perso, ) le 03/08/2004 à 13:30. (lien). Évalué à 1.Je connaissais le tee (bien pratique) mais par contre, je ne suis pas arrivé à le faire marcher avec exec.
Justement, je veux éviter d'avoir à lancer les commandes shell comme ça :
./script.sh 2>&1 | tee script.log
Mais ça me donne une idée ...
En fait il faudrait dupliquer les file descriptors out (1) et err(2) comme le ferait un tee, afficher le 1 et le 2 à l'écran, et diriger les duplicats vers deux fichiers...
je vais finir par trouver :) je sens que je suis pas loin !-
[^]Re: Take a cup of tee
Posté par totof2000 () le 03/08/2004 à 13:49. (lien). Évalué à 1.Ma solution ne marche pas en arriere plan :(
-
[^]Re: Take a cup of tee
Posté par totof2000 () le 03/08/2004 à 14:17. (lien). Évalué à 1.Pour que ma solution marche en arriere plan, il faut tester le code retour de la commande who -m.
Si elle échoue, SORTIE=/dev/null-
[^]Re: Take a cup of tee
Posté par totof2000 () le 03/08/2004 à 14:44. (lien). Évalué à 1.Voici une variante qui pourrait marcher comme tu le demande.
J'ai pas de linux sous la main, peux-tu me dire si who -m fonctionne comme sous aix ?
#!/bin/ksh
# Identification du pseudo-terminal de sortie
SORTIE=/dev/$((who -m 2>/dev/null || echo "toto null") |awk '{ print $2}')
echo $SORTIE
myexec() {
# Commande:
($* | tee titi.log>$SORTIE)2>&1 | tee error.log >$SORTIE
}
myexec ls - toto-
[^]Re: Take a cup of tee
-
-
-
-
est-ce que perl est un shell ?
je laisse la question fameuse "est-ce que perl est un shell ?" de côté et je t'indique comment faire en perl :
open STDOUT, "|tee stdout";
open STDERR, "|tee stderr >&2";
et puis même que si tu es vraiment masochiste et que tu veux quand même utiliser bash ça te donnera une idée poir réussir à le faire en bash.
Une solution en Shell
A mon avis, la seule solution pour le faire en shell est d'utiliser mkfifo :
$> mkfifo mon_pipe
$> ma_commande 2>mon_pipe | tee out.log &
$> cat mon_pipe | tee err.log
Sans oublier de faire :
$> rm mon_pipe
à la fin de la manipulation.
pas évident
Je me suis déjà +/- battu avec ce problème, et je n'ai pas de solution complètement satisfaisante. Je te mets ici une version verbosement commentée de ma solution la plus simple :
http://tdegreni.free.fr/files/foobar.sh(...)
Le problème qui persiste est que stdout et stderr ne sont pas synchronisés, et que donc des messages rapidement enchainés sur chacune de ses sorties peuvent se retrouver entrelacés sur le terminal. En fait, je ne vois pas vraiment de solution à ce problème : la duplication des deux flux passe forcement par des processus concurrents (les deux 'tee'), qui sont bufferisés, et on n'a pas le contrôle de leur ordonnancement. Peux être qu'en C on pourrait faire un seul processus pour consommer et dupliquer les deux flux alternativement (et vu que côté producteur l'écriture sur des pipes est bloquante, on ne perdrait pas la synchro), bref on pourrait faire un genre de double-tee, mais en shell par contre je ne vois vraiment pas.
À part ça, tu verras que dans mon script je n'ai pas distingué shell interactif de shell non-interactif. Il me semble d'ailleurs que tout ce qui est mis dans un script est non-interactif, sauf à forcer ça avec un "#!/bin/bash -i". Je ne crois pas que ton test sur $PS1 fonctionne comme tu l'attends, parceque $PS1 n'est pas censé être exporter. Moi en général, quand je veux appeler qqch depuis un cron sans pourrir mon log, je ne compte pas sur le script lui même, mais je fais mon appel avec "&>/dev/null", et puis voilà.
Bon ceci dit, si tu tiens à tester ça au niveau du script, alors y'a peut être moyen plutôt avec $TERM, ou encore avec la commande 'tty', je sais pas trop... Je sais qu'en python par exemple, je ferais ça avec le prédicat "sys.stdout.isatty()", mais en bash, j'ai jamais essayer de trouver un équivalent. Si tu trouves, alors dans mon script ce sera facile de rajouter le test pour faire un appel récursif avec une redirection plus simple dans le cas non-interactif (genre '$0 "${@}" 1>${STDOUT_LOG} 2>${STDERR_LOG}').
-
[^]Re: pas évident
-
[^]Re: pas évident
Posté par tgl () le 03/08/2004 à 14:21. (lien). Évalué à 2.Ou encore +/- le même en explicitant la création des fifo et des processus d'arrière plan au lieu d'utiliser des pipes, comme proposé plus haut (plutôt plus lourd amha) :
http://tdegreni.free.fr/files/foobar2.sh(...)
QQ chose très crade comme ça ?
echo -n > out.log
echo -n > err.log
tail -f out.log &
tail -f err.log &
ls > out.log >& err.log && sleep 1
killall tail
C'est très crade...
Remplacer killall tail pas qq chose de moins... destructif serait une bonne idée, mais j'ai pas trop le temps, je vous livre juste ça comme ça pour vous donner des idée...
Revenir en haut de page || Retourner aux forums || Retourner au forum Programmation.shell



Cette discussion est archivée, il n'est plus possible de laisser des commentaires.
Note : les commentaires appartiennent à ceux qui les ont postés. Nous n'en sommes pas responsables.