web-dev-qa-db-fra.com

Portée variable Bash

Veuillez m'expliquer pourquoi la toute dernière déclaration echo est vide? Je suppose que XCODE est incrémenté dans la boucle while à la valeur 1:

#!/bin/bash
OUTPUT="name1 ip ip status" # normally output of another command with multi line output

if [ -z "$OUTPUT" ]
then
        echo "Status WARN: No messages from SMcli"
        exit $STATE_WARNING
else
        echo "$OUTPUT"|while read NAME IP1 IP2 STATUS
        do
                if [ "$STATUS" != "Optimal" ]
                then
                        echo "CRIT: $NAME - $STATUS"
                        echo $((++XCODE))
                else
                        echo "OK: $NAME - $STATUS"
                fi
        done
fi

echo $XCODE

J'ai essayé d'utiliser l'instruction suivante à la place du ++XCODE méthode

XCODE=`expr $XCODE + 1`

et il n'imprimera pas non plus en dehors de la déclaration while. Je pense que je manque quelque chose à propos de la portée variable ici, mais la vieille page de manuel ne me le montre pas.

102
Matt P

Parce que vous dirigez la boucle while, un sous-shell est créé pour exécuter la boucle while.

Maintenant, ce processus enfant a sa propre copie de l'environnement et ne peut transmettre aucune variable à son parent (comme dans tout processus unix).

Par conséquent, vous devrez vous restructurer pour ne pas vous perdre dans la boucle. Vous pouvez également exécuter une fonction, par exemple, et echo la valeur à renvoyer par le sous-processus.

http://tldp.org/LDP/abs/html/subshells.html#SUBSHELL

109
pixelbeat

Le problème est que les processus assemblés avec un canal sont exécutés dans des sous-shell (et ont donc leur propre environnement). Tout ce qui se passe dans le while n’affecte rien en dehors du tuyau.

Votre exemple spécifique peut être résolu en réécrivant le tuyau en

while ... do ... done <<< "$OUTPUT"

ou peut-être

while ... do ... done < <(echo "$OUTPUT")
102
mweerden

Cela devrait également fonctionner (car echo et while sont dans le même sous-shell):

#!/bin/bash
cat /tmp/randomFile | (while read line
do
    LINE="$LINE $line"
done && echo $LINE )
8
sano

Une autre option:

#!/bin/bash
cat /some/file | while read line
do
  var="abc"
  echo $var | xsel -i -p  # redirect stdin to the X primary selection
done
var=$(xsel -o -p)  # redirect back to stdout
echo $var

EDIT: Ici, xsel est une nécessité (installez-le). Vous pouvez aussi utiliser xclip: xclip -i -selection clipboard au lieu de xsel -i -p

3
Rammix
 #!/bin/bash
 OUTPUT="name1 ip ip status"
+export XCODE=0;
 if [ -z "$OUTPUT" ]
----

                     echo "CRIT: $NAME - $STATUS"
-                    echo $((++XCODE))
+                    export XCODE=$(( $XCODE + 1 ))
             else

echo $XCODE

voir si ces changements aident

1
Kent Fredric

Une autre option consiste à exporter les résultats dans un fichier du sous-shell, puis à les lire dans le shell parent. quelque chose comme

#!/bin/bash
EXPORTFILE=/tmp/exportfile${RANDOM}
cat /tmp/randomFile | while read line
do
    LINE="$LINE $line"
    echo $LINE > $EXPORTFILE
done
LINE=$(cat $EXPORTFILE)
0
freethinker

J'ai contourné ça quand je fabriquais mon propre petit duo:

ls -l | sed '/total/d ; s/  */\t/g' | cut -f 5 | 
( SUM=0; while read SIZE; do SUM=$(($SUM+$SIZE)); done; echo "$(($SUM/1024/1024/1024))GB" )

Le fait est que je crée un sous-shell avec () contenant ma variable SOMME et le moment, mais que je me faufile dans la totalité () au lieu de dans la durée elle-même, ce qui évite le gotcha.

0
Adrian May