10 votes

Comment obtenir à la fois PIPESTATUS et la sortie en bash script

J'essaye d'obtenir la date de dernière modification d'un fichier avec cette commande

TM_LOCAL=`ls -l --time-style=long-iso ~/.vimrc | awk '{ print $6" "$7 }'`

TM_LOCAL a une valeur comme "2012-05-16 23:18" après l'exécution de cette ligne

J'aimerais aussi vérifier PIPESTATUS pour voir s'il y a eu une erreur. Par exemple, si le fichier n'existe pas, ls rendements 2. Mais $? a la valeur 0 car il a la valeur de retour de awk .

Si je lance cette commande seule, je peux vérifier la valeur de retour de ls en regardant ${PIPESTATUS[0]}

ls -l --time-style=long-iso ~/.vimrc | awk '{ print $6" "$7 }'

Aber $PIPESTATUS ne fonctionne pas comme prévu si j'assigne la sortie à une variable comme dans le premier exemple. Dans ce cas, $PIPESTATUS a seulement 1 élément qui est le même que $?

Donc, la question est, comment puis-je obtenir à la fois $PIPESTATUS et assigner la sortie à une variable en même temps ?

10voto

givp Points 798

Tu pourrais faire ça :

TM_LOCAL=$(ls -l --time-style=long-iso ~/.vimrc | \
             awk '{ print $6" "$7 }' ; exit ${PIPESTATUS[0]} )

Entonces $? sera le code de retour de ls . Cela ne fonctionne pas si vous avez besoin du code de retour de plus d'une des parties du pipeline (mais vous pourriez diviser le pipeline si la sortie n'est pas trop grande, comme c'est le cas ici).

Voici un moyen plutôt onéreux d'obtenir l'intégralité des données. PIPESTATUS et la sortie. Pas très élégant, mais je n'ai rien trouvé d'autre :

result=$(echo -e "a\nb\nc" | \
          ( cat ; exit 1 ) | \
          ( cat ; exit 42 ) ; echo ${PIPESTATUS[@]})
output=$(head -n -1 <<< "$result")
status=($(tail -n 1 <<< "$result"))
echo "Output:"
echo "$output"
echo "Results:"
echo "${status[@]}"

Ce qui donne :

Output:
a
b
c
Results:
0 1 42

4voto

Daniel Beck Points 105590

Utilice set -o pipefail en bash pour obtenir le code de sortie non-zéro le plus à droite dans une séquence de commandes en pipeline comme $? . De man bash :

Si elle est définie, la valeur de retour d'un pipeline est la valeur de la dernière commande (la plus à droite) à sortir avec un état non nul, ou zéro si toutes les commandes du pipeline sortent avec succès. Cette option est désactivée par défaut.

Ensuite, vous pouvez simplement accéder $? . Utilisez set +o pipefail pour le désactiver à nouveau.

3voto

toddkaufmann Points 211

Le principal problème avec "ce que vous attendez" est qu'une commande entre guillemets est exécutée dans un sous-shell ; $PIPESTATUS existe à cet endroit et l'état renvoyé par celui-ci suit les mêmes règles que si vous exécutiez un seul exécutable (ou Shell Shell). Le statut de la commande backquote est celui de la commande la plus à droite ( awk ) statut.

Pour mettre en œuvre ce que @ Daniel Beck dit, mettre le pipefail dans le sous-système de la manière suivante :

TM_LOCAL=`set -o pipefail; ls -l --time-style=long-iso ~/.vimrc | awk '{ print $6" "$7 }'` maintenant le statut stocké dans $? ensuite, le statut de ls (si non nul).

Cependant, je pense qu'un explicite if [ -f ~/.vimrc ]; ... le test serait plus lisible.

Tu ne peux pas mettre la sortie dans une variable et PIPESTATUS retourné sans fichier temporaire pour le premier, ou sans marshalling du second dans une chaîne.

2voto

dev-segal Points 13

Je suppose que le problème ici est que PIPESTATUS disparaît dans son intégralité dès que vous exécutez une commande. Vous pouvez obtenir le tableau complet de PIPESTATUS dans bash version 2 ou supérieure de cette façon :

declare -a status
status=(${PIPESTATUS[@]})

Puis accéder ${status[0]} , ${status[1]} , usw.

0voto

chepner Points 6381

Une option consiste à vérifier l'existence de votre fichier avant de l'utiliser. d'obtenir son temps de modification avec un appel à stat . Puisque stat renvoie un peu plus que ce que vous voulez dans le timestamp, vous pouvez le réduire en utilisant l'expansion des paramètres.

Avec GNU stat (par exemple sous Linux), vous pouvez exécuter :

[[ -f ~/.vimrc ]] && TM_LOCAL=$(stat -c '%y' ~/.vimrc 2>/dev/null)
TM_LOCAL=${TM_LOCAL%:*}  # Safe to do, even if stat fails

Sur Mac OS X et d'autres systèmes BSD, stat La syntaxe diffère et peut spécifier un format de temps :

[[ -f ~/.vimrc ]] && TM_LOCAL=$(stat -f '%Sm' -t '%Y-%m-%d %H:%M' ~/.vimrc 2>/dev/null)

SistemesEz.com

SystemesEZ est une communauté de sysadmins où vous pouvez résoudre vos problèmes et vos doutes. Vous pouvez consulter les questions des autres sysadmins, poser vos propres questions ou résoudre celles des autres.

Powered by:

X