2017-05-23 2 views
1

Le langage de programmation Crystal n'écrit pas actuellement dans STDERR en cas d'échec de la compilation. J'ai besoin de rediriger STDOUT vers STDERR si le statut de sortie n'est pas 0 et toujours retourner le statut de sortie.Rediriger STDOUT vers STDERR lorsque l'état de sortie n'est pas 0 dans Bash

+0

Avez-vous essayé 'some_bash_command.sh 2> & 1' – t0mm13b

+1

Les redirections sont exécutées ** avant ** un programme est démarré. Le statut de sortie n'est connu que ** après ** ce programme se termine. Tu ne peux pas remonter le temps. –

Répondre

3

Pris littéralement, votre requête est littéralement impossible: Les redirections sont effectuées avant le démarrage d'une commande, alors que le statut de sortie n'est connu qu'à sa sortie.

Cependant, vous pouvez inconditionnellement rediriger dans un tampon, puis écrire ce tampon soit stdout ou stderr après que l'état de sortie est connu.

Considérons une enveloppe semblable à ce qui suit:

#!/bin/sh 
if output=$("[email protected]"); then 
    printf '%s\n' "$output" 
else 
    retval=$? 
    printf '%s\n' "$output" >&2 
    exit "$retval" 
fi 

... invoquée (si cela est enregistré en tant que stderr-wrapper):

stderr-wrapper your-program arg1 arg2 ... 
+0

C'est tellement génial! Merci beaucoup! Il n'a pas eu d'effets secondaires pour les autres chemins heureux. –

+0

Il ya * une mise en garde ici dans la mesure où ce code va manger des NUL qui pourraient être inclus dans la sortie de votre programme (car les NUL ne peuvent pas être stockées dans les chaînes C, qui bash utilise le stockage en mémoire). Si c'est un problème, vous pouvez écrire dans un fichier. –

+1

Si la sortie attendue est trop importante, un fichier temporaire peut être plus sûr –

1

méthode de conduite Rond-point, ce qui nécessite tac et sans danger eval, mais ni les variables de tampon, ni les fichiers temporaires.

script démonstration demo, en utilisant echo false ; false pour simuler un programme qui génère à stdout et renvoie un code d'erreur "".

#!/bin/bash 
out=([0]=/dev/stdout [1]=/dev/stderr) 
{ { echo $1 ; $1 ; echo $? ; } | tac ; } | \ 
    { read x ; eval tac \> ${out[$x]} ; exit $x ; } 

Preuve, en utilisant annotate-output:

annotate-output +'' ./demo true ; echo --- ; annotate-output +'' ./demo false 
I: Started ./demo true 
O: true 
I: Finished with exitcode 0 
--- 
I: Started ./demo false 
E: false 
I: Finished with exitcode 1 

Généraliser qui demo en stderr-wrapper:

  1. Pour bash:

    #!/bin/bash 
    # Usage: stderr-wrapper program [ args... ] 
    out=([0]=/dev/stdout [1]=/dev/stderr) 
    { { [email protected] ; echo $? ; } | tac ; } | \ 
    { read x ; eval tac \> ${out[$((x>0))]} ; exit $x ; } 
    
  2. Pour POSIX coquilles, (ici il est dash):

    #!/bin/dash 
    # Usage: stderr-wrapper program [ args... ] 
    { { "[email protected]" ; echo $? ; } | tac ; } | \ 
    { read x ; eval tac 1\>\&$(((x>0)+1)) ; exit $x ; } 
    

Comment la version bash fonctionne:

  1. Exécutez le programme incriminé, qui sort à stdout .
  2. Imprimez le code d'erreur juste après, également stdout.
  3. Inversez le flux entier avec tac, le code d'erreur est donc le premier. (Cher si le flux est long.)
  4. read une ligne, le code d'erreur, stocker dans $x.
  5. eval le membre du groupe $out qui correspond au périphérique sur lequel la sortie doit aller, puis de revenir en arrière sur la sortie avec tac sur ce périphérique.