Змінна область Bash


104

Будь ласка, поясніть мені, чому саме остання 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. Я думаю, що мені тут щось не вистачає про змінну область, але сторінка man не показує мені це.


Де ви ініціалізуєте XCODE на те, що можна збільшити?
Пол Томблін

Я намагався кинути "XCODE = 0" у верхню частину коду, поза тим, як заява "while"
Matt P

Без суглоба це працює для мене. #! / bin / bash for i in 1 2 3 4 5; do echo $ ((++ XCODE)) зроблено echo "fin:" $ XCODE Я думаю, що ваша проблема не має нічого спільного із змінним масштабуванням та усім, що стосується того, що відбувається в той час.
Пол Томблін

Згоден .. здається, що це стосується циклу "під час читання"?
Мет П

Про це є відповідь на Bash: mywiki.wooledge.org/BashFAQ/024
Фабіо каже

Відповіді:


117

Оскільки ви знаходитесь у циклі while, створюється підзагін для запуску циклу while.

Тепер цей дочірній процес має власну копію оточення і не може передавати жодні змінні назад своєму батьківському (як у будь-якому процесі Unix).

Тому вам потрібно буде реструктурувати так, щоб ви не працювали в циклі. Крім того, ви можете запустити функцію, наприклад, і echoзначення, яке потрібно повернути з підпроцесу.

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


2
це просто відповіло на стільки випадкових випадкових питань, з якими я зіткнувся з баш сценаріями.
Даніель Аганс

Ця ідеальна відповідь мене дуже засмучує і пояснює дійсно дивну поведінку в нашій системі ІС.
KayCee

108

Проблема полягає в тому, що процеси, складені разом з трубою, виконуються в підрозділах (і тому мають своє середовище). Що б не сталося всередині, whileце не впливає на те, що знаходиться поза трубою.

Ваш конкретний приклад можна вирішити, переписавши трубку на

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

чи, можливо,

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

32
Для тих, хто дивиться на це плутанина щодо того, що таке весь синтаксис <() (як я), він називається "Заміна процесів", а конкретне використання, докладно описане
Росс Ейкен

2
Заміна процесу - це те, що кожен повинен регулярно використовувати! Це дуже корисно. Я роблю щось подібне vimdiff <(grep WARN log.1 | sort | uniq) <(grep WARN log.2 | sort | uniq)щодня. Вважайте, що ви можете використовувати декілька одночасно та обробляти їх як файли ... МОЖЛИВОСТІ!
Бруно Броноський

8

Це також має працювати (адже відлуння і час знаходяться в одній нижній частині):

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

3

Ще один варіант:

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


Я отримую помилку: ./scraper.sh: рядок 111: xsel: команда не знайдена ./scraper.sh: рядок 114: xsel: команда не знайдена
3kstc

@ 3kstc очевидно, встановіть xsel. Також ви можете використовувати xclip, але його використання дещо інше. Основний момент тут: 1-й ви поміщаєте вихід у буфер обміну (3 з них в Linux), 2-й - ви захоплюєте його звідти і відправляєте в stdout.
Rammix

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

подивіться, чи допомагають ці зміни


Роблячи це, я отримую "0" для друку останньої заяви ехо. однак я очікую, що значення буде 1, а не нульове. Крім того, навіщо використовувати експорт? Я припускаю, що це примушує його до навколишнього середовища?
Мет П

0

Іншим варіантом є виведення результатів у файл із допоміжної оболонки, а потім їх зчитування у батьківській оболонці. щось на зразок

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

0

Я обійшов це, коли робив своє маленьке ду:

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 і час, але я вставляю в ціле (), а не в той самий час, що уникає гатчі.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.