Bash переменная область видимости

Пожалуйста, объясните мне, почему последнее echo утверждение пустое? Я ожидаю, что XCODE увеличивается в цикле while до значения 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

Я попытался использовать следующее утверждение вместо метода ++XCODE

XCODE='expr $XCODE + 1'

и это тоже не будет печататься вне оператора while. Я думаю, что я что-то упускаю из области видимости переменной, но старая страница руководства не показывает это мне.

Ответ 1

Поскольку вы подключаетесь к циклу while, создается субоболочка для запуска цикла while.

Теперь этот дочерний процесс имеет свою собственную копию среды и не может передать переменные обратно к его родителю (как в любом процессе Unix).

Поэтому вам нужно будет реструктурировать так, чтобы вы не включились в цикл. В качестве альтернативы вы можете запустить функцию, например, и echo значение, которое вы хочу вернуть из подпроцесса.

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

Ответ 2

Проблема состоит в том, что процессы, связанные с трубой, выполняются в подоболочках (и, следовательно, имеют собственную среду). Все, что происходит внутри while, не влияет на что-либо вне трубы.

Ваш конкретный пример можно решить, переписав канал на

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

или, возможно,

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

Ответ 3

Это также должно работать (потому что эхо и while находятся в одной подоболочке):

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

Ответ 4

Еще один вариант:

#!/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: Здесь xsel является требованием (установите его). Кроме того, вы можете использовать xclip:   xclip -i -selection clipboard вместо   xsel -i -p

Ответ 5

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

посмотреть, помогают ли эти изменения

Ответ 6

Другой вариант - вывести результаты в файл из подоболочки и затем прочитать его в родительской оболочке. что-то вроде

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

Ответ 7

Я обошел это, когда я делал свой собственный маленький дю:

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

Дело в том, что я создаю подоболочку с(), содержащую мою переменную SUM и while, но я транслирую в целое(), а не в то самое время, которое позволяет избежать получения.