Alcance variable de Bash


87

Por favor, explíqueme por qué la última declaración de "eco" está en blanco? Espero que se incrementa en el bucle while para un valor de 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 

He intentado usar la siguiente declaración en lugar del método ++ XCODE

XCODE=`expr $XCODE + 1` 

de impresión y también suele fuera de la declaración while. Creo que me falta algo sobre el alcance variable aquí, pero la página de ol 'man no me lo está mostrando.

  0

¿Dónde se inicializa XCODE a algo que se puede incrementar? 23 sep. 082008-09-23 21:57:56

  0

He intentado lanzar un "XCODE = 0" en la parte superior del código, fuera de la declaración while 23 sep. 082008-09-23 21:59:21

  0

Sin el cruft, me funciona. #!/Bin/bash para i en 1 2 3 4 5; do echo $ ((++ XCODE)) hecho echo "fin:" $ XCODE Creo que su problema no tiene nada que ver con el alcance variable y todo que ver con lo que está sucediendo en el tiempo. 23 sep. 082008-09-23 22:08:23

  0

De acuerdo ... parece que tiene que ver con el ciclo "while read"? 23 sep. 082008-09-23 22:11:27

91

Porque estás tubería en el bucle while, se crea un shell secundario para ejecutar el bucle while. Ahora este proceso hijo tiene su propia copia del entorno y no puede pasar ninguna variable a su padre (como en cualquier proceso de Unix).

Por lo tanto, tendrá que reestructurar para no estar metido en el circuito. Alternativamente, podría ejecutar una función, por ejemplo, y repetir el valor que desea devolver del subproceso.

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

  0

Tiene sentido ... Gracias. Parece que la función es el camino a seguir para mí. 23 sep. 082008-09-23 22:36:03

+1

esto acaba de responder tantos de los problemas aparentemente aleatorios que me estaba encontrando con bash scripting. 27 ene. 152015-01-27 14:29:10

  0

Esta respuesta perfecta me molesta mucho y explica un comportamiento realmente extraño en nuestro sistema de CI. 06 abr. 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 

ver si esos cambios ayudan

  0

Al hacer esto, ahora obtengo un "0" para imprimir para la última declaración de eco. sin embargo, espero que el valor sea 1, no cero. Además, ¿por qué el uso de la exportación? ¿Supongo que eso lo fuerza al medio ambiente? 23 sep. 082008-09-23 22:09:59


93

El problema es que los procesos que junto con un tubo se ejecutan en subniveles (y por lo tanto tienen su propio entorno). Lo que ocurra dentro del while no afecta nada fuera de la tubería.

Su ejemplo específico puede ser resuelto por la reescritura de la tubería para

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

o tal vez

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

Brillante. No había visto la <sintaxis antes, así que tendré que leer sobre ella, pero esto funciona como un regalo. Parece extraño tener el comando de entrada al final en lugar de al principio, pero funciona. 31 oct. 082008-10-31 19:32:03

+3

Tampoco conocía la sintaxis '<(command)', y esto me ha ahorrado mucho tiempo y dolores de cabeza. un gran +1 para ti señor :) 30 ene. 132013-01-30 12:29:39

+26

Para aquellos que están confundidos en cuanto a lo que es la sintaxis <() completa (como yo), se llama "Sustitución de procesos", y el uso específico detallado anteriormente puede ser visto aquí: http://mywiki.wooledge.org/ProcessSubstitution 19 feb. 132013-02-19 14:53:46

  0

* gracias * ¡esto era exactamente lo que estaba buscando! 04 abr. 142014-04-04 03:37:17


0

Otra opción es dar salida a los resultados en un archivo de la subcapa y luego lo leen en el cáscara del padre. algo así como

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

3

Una de las opciones más:

#!/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: Aquí, XSEL es un requisito (instalarlo). Como alternativa, puede utilizar xclip: xclip -i -selection clipboard en lugar de xsel -i -p

  0

Aparece un error: ./scraper.sh: línea 111: xsel: comando no encontrado ./scraper.sh: línea 114: xsel: comando no encontrado 19 abr. 162016-04-19 01:57:49

  0

@ 3kstc obviamente, instale xsel. Además, puedes usar xclip, pero su uso es un poco diferente. Punto principal aquí: primero pones la salida en un portapapeles (3 de ellos en Linux), 2º: lo agarras desde allí y lo envías a stdout. 09 may. 162016-05-09 20:43:39


4

Esto debería funcionar también (debido eco y mientras están en el mismo subnivel):

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

0

llegué alrededor de este cuando estaba haciendo mi pequeño 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") 

el punto es que hago un subnivel con() que contiene mi variable de SUMA y al mismo tiempo, pero canalizo en el todo() en vez de en el tiempo mismo, lo que evita el gotcha.