Bash 변수 범위


104

마지막 echo문장이 비어있는 이유를 설명해주세요 . XCODEwhile 루프에서 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 문 외부에서는 인쇄되지 않습니다. 여기서 변수 범위에 대한 내용이 누락 된 것 같지만 맨 페이지에 표시되지 않습니다.


증가 할 수있는 것으로 XCODE를 어디에서 초기화합니까?
Paul Tomblin

나는 while 문 밖에서 코드 상단에 "XCODE = 0"을 던지려고했다
Matt P

딱딱하지 않으면 저에게 효과적입니다. #! / bin / bash for i in 12 34 5; do echo $ ((++ XCODE)) done echo "fin :"$ XCODE 난 당신의 문제는 변수 범위와 그동안 무슨 일이 일어나고 있는지와 관련이 없다고 생각합니다.
Paul Tomblin

동의합니다 .. "while read"루프와 관련이있는 것 같습니다.
Matt P

이것에 대해 배쉬 자주 묻는 질문이있다 : mywiki.wooledge.org/BashFAQ/024
파비오는 분석 재개 모니카 말한다

답변:


117

while 루프로 배관하기 때문에 while 루프를 실행하기 위해 하위 쉘이 생성됩니다.

이제이 자식 프로세스는 환경의 자체 복사본을 가지고 있으며 모든 변수를 부모에게 다시 전달할 수 없습니다 (모든 유닉스 프로세스에서와 같이).

따라서 루프에 배관하지 않도록 구조를 변경해야합니다. 또는 예를 들어 함수에서 실행 echo하고 하위 프로세스에서 반환하려는 값을 실행할 수 있습니다 .

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


2
이것은 내가 bash 스크립팅으로 겪었던 겉보기에 무작위로 보이는 많은 문제에 답했습니다.
Daniel Agans

이 완벽한 대답은 나를 너무 화나게하고 우리 CI 시스템에서 정말 이상한 행동을 설명합니다.
KayCee

108

문제는 파이프와 함께 결합 된 프로세스가 서브 쉘에서 실행된다는 것입니다 (따라서 자체 환경이 있음). 내부에서 일어나는 while일은 파이프 외부에 영향을 미치지 않습니다.

파이프를 다음과 같이 다시 작성하여 특정 예를 해결할 수 있습니다.

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

또는 아마도

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

32
전체 <() 구문이 (저와 같이) 무엇인지 혼란스러워하는 사람들을 위해 이것은 "Process Substitution"이라고 불리며 위에서 자세히 설명 된 구체적인 사용법은 mywiki.wooledge.org/ProcessSubstitution에서
Ross Aiken

2
프로세스 대체는 모든 사람이 정기적으로 사용해야하는 것입니다! 매우 유용합니다. 나는 vimdiff <(grep WARN log.1 | sort | uniq) <(grep WARN log.2 | sort | uniq)매일 같은 일을한다. 한 번에 여러 개를 사용할 수 있고 파일처럼 취급 할 수 있습니다. 가능성!
Bruno Bronosky 2018

8

이것도 작동합니다 (echo와 while이 동일한 서브 쉘에 있기 때문에) :

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

편집 : 여기에서 xsel은 요구 사항입니다 (설치). 또는 xclip : xclip -i -selection clipboard 대신 xsel -i -p


./scraper.sh : 라인 111 : XSEL : 나는 오류 get 명령을 찾을 수 없습니다 ./scraper.sh : 라인 114 : XSEL : 명령을 찾을 수 없습니다
3kstc

@ 3kstc 분명히 xsel을 설치하십시오. 또한 xclip을 사용할 수 있지만 사용법이 약간 다릅니다. 여기서 요점 : 먼저 출력을 클립 보드에 넣습니다 (리눅스에서 3 개), 두 번째-거기에서 가져 와서 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

이러한 변화가 도움이되는지 확인


이 작업을 수행 할 때 마지막 echo 문을 인쇄 할 "0"이 표시됩니다. 그러나 값은 0이 아닌 1이 될 것으로 예상합니다. 또한 왜 수출을 사용합니까? 나는 그것이 환경에 강요한다고 가정합니까?
Matt P

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

나는 내 자신의 작은 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" )

요점은 SUM 변수와 while을 포함하는 ()로 하위 쉘을 만들지 만 while 자체가 아닌 전체 ()로 파이프하여 문제를 피한다는 것입니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.