Bash scope variabile


87

Mi spieghi perché l'ultima istruzione "echo" è vuota? Mi aspetto che è stato incrementato nel ciclo while per un valore pari a 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 

Ho provato con la seguente dichiarazione al posto del metodo di ++ XCODE

XCODE=`expr $XCODE + 1` 

e stampa troppo wont al di fuori della dichiarazione while. Penso che mi manchi qualcosa sull'ampiezza variabile qui, ma la pagina del vecchio man non me lo mostra.

  0

Dove inizializzare XCODE in qualcosa che può essere incrementato? 23 set. 082008-09-23 21:57:56

  0

Ho provato a lanciare un "XCODE = 0" nella parte superiore del codice, al di fuori dell'istruzione while 23 set. 082008-09-23 21:59:21

  0

Senza il cruft, funziona per me. #!/Bin/bash per i in 1 2 3 4 5; do echo $ ((++ XCODE)) fatto echo "pinna:" $ XCODE Penso che il tuo problema non abbia nulla a che fare con l'ambito della variabile e tutto quello che sta accadendo nel mentre. 23 set. 082008-09-23 22:08:23

  0

D'accordo .. sembra che abbia a che fare con il ciclo "while read"? 23 set. 082008-09-23 22:11:27

91

Perché si sta tubazioni nel ciclo while, viene creata una sotto-shell per eseguire il ciclo while. Ora questo processo figlio ha la propria copia dell'ambiente e non può passare alcuna variabile al suo genitore (come in qualsiasi processo unix).

Pertanto, sarà necessario ristrutturare in modo da non essere collegati al circuito. In alternativa è possibile eseguire in una funzione ad esempio ed echo il valore che si desidera restituire da dal processo secondario.

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

  0

Ha senso .. Grazie. Sembra che la funzione sia la strada giusta per me. 23 set. 082008-09-23 22:36:03

+1

questo ha risposto solo a molti dei problemi apparentemente casuali che stavo incontrando con bash scripting. 27 gen. 152015-01-27 14:29:10

  0

Questa risposta perfetta mi sconvolge così tanto e spiega un comportamento davvero strano nel nostro sistema di CI. 06 apr. 172017-04-06 08:29:48


1
#!/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 

vedere se questi cambiamenti contribuiscono

  0

Quando faccio questo, ora ottengo uno "0" per stampare l'ultima istruzione echo. tuttavia mi aspetto che il valore sia 1 non zero. Inoltre, perché l'uso di esportazione? Suppongo che lo costringa nell'ambiente? 23 set. 082008-09-23 22:09:59


93

Il problema è che i processi messi insieme con un tubo vengono eseguiti in subshells (e quindi avere il proprio ambiente). Qualunque cosa accada all'interno dello while non ha effetto su nulla al di fuori del tubo.

vostro esempio specifico può essere risolto riscrivendo il tubo

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

o forse

while ... do ... done < <(echo "$OUTPUT") 
+1

Brillante. Non avevo ancora visto la sintassi <<, quindi dovrò leggerlo, ma questo funziona benissimo. È strano avere il comando di input alla fine piuttosto che all'inizio, ma funziona. 31 ott. 082008-10-31 19:32:03

+3

Inoltre non conoscevo la sintassi '<(comando)', e questo mi ha risparmiato un sacco di tempo e mal di testa. un grande +1 a voi signore :) 30 gen. 132013-01-30 12:29:39

+26

Per coloro che guardano a questo confuso su quale sia l'intera sintassi <() è (come lo ero io), si chiama "Process Substitution", e l'uso specifico sopra dettagliato può essere visto qui: http://mywiki.wooledge.org/ProcessSubstitution 19 feb. 132013-02-19 14:53:46

  0

* grazie * questo era esattamente quello che stavo cercando! 04 apr. 142014-04-04 03:37:17


0

Un'altra opzione è quella di produrre i risultati in un file dalla subshell e poi leggere nel shell genitore. qualcosa come

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

3

Un'altra opzione:

#!/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: Qui, Xsel è un requisito (installarlo). In alternativa, è possibile utilizzare xclip: xclip -i -selection clipboard invece di xsel -i -p

  0

Viene visualizzato un errore: ./scraper.sh: riga 111: xsel: comando non trovato ./scraper.sh: riga 114: xsel: comando non trovato 19 apr. 162016-04-19 01:57:49

  0

@ 3kstc ovviamente, installare xsel. Inoltre, è possibile utilizzare xclip, ma il suo utilizzo è leggermente diverso. Punto principale qui: 1 ° metti l'output in un clipboard (3 di questi in linux), 2 ° - lo prendi da lì e lo mandi a stdout. 09 mag. 162016-05-09 20:43:39


4

Questo dovrebbe funzionare così (perché eco e mentre sono in stessa subshell):

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

0

ho avuto intorno a questo quando stavo facendo il mio piccolo du:

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") 

il punto è che faccio una subshell con() contenente mia variabile SUM e il tempo, ma io inserisco l'intero() invece che nel mentre stesso, che evita il trambusto.