bash : 읽기 루프가 끝나면 변수가 값을 잃습니다. 그렇지 않은 경우를 제외하고. “Count is 0″을

쉘 스크립트 중 하나에 문제가 있습니다. 동료 몇 명에게 물어 보았지만 모두 머리를 흔드는 것 (긁힘 후)으로 답을 찾아 왔습니다.

내 이해에 따르면 다음 쉘 스크립트는 “Count is 5″를 마지막 줄로 인쇄해야합니다. 그렇지 않은 경우를 제외하고. “Count is 0″을 인쇄합니다. “while read”가 다른 종류의 루프로 바뀌면 제대로 작동합니다. 스크립트는 다음과 같습니다.

에코 "1"> 입력 데이터
에코 "2">> 입력 데이터
에코 "3">> 입력 데이터
에코 "4">> 입력 데이터
에코 "5">> 입력 데이터

CNT = 0

고양이 input.data | 읽는 동안;
해야 할 것
  CNT ++하자;
  echo "$ CNT에 계산"
끝난
echo "개수는 $ CNT입니다"

왜 이런 일이 발생하며 어떻게 방지 할 수 있습니까? Debian Lenny와 Squeeze에서 동일한 결과 (예 : bash 3.2.39 및 bash 4.1.5)에서 이것을 시도했습니다. 쉘 스크립트 마법사가 아니라는 것을 완전히 인정하므로 모든 의견을 부탁드립니다.



답변

인수 @ Bash FAQ 항목 # 24 : “루프에 변수를 설정했습니다. 루프가 종료 된 후 변수가 갑자기 사라지는 이유는 무엇입니까? 또는 데이터를 읽을 수없는 파이프는 무엇입니까?” (가장 최근에 여기 에 보관 됨 ).

요약 : 이것은 bash 4.2 이상에서만 지원됩니다. bash를 사용하는 경우 파이프 대신 명령 대체와 같은 다른 방법을 사용해야합니다.


답변

이것은 일종의 ‘일반적인’실수입니다. 파이프는 SubShell을 작성하므로 while read스크립트와 다른 쉘에서 실행 되므로 CNT변수가 변경되지 않습니다 (파이프 서브 쉘 내부의 변수 만).

마지막 echo으로 하위 셸 while을 그룹화하여 수정하십시오 (고칠 수있는 다른 방법이 많이 있습니다. 이것은 하나입니다. Iain과 Ignacio의 답변에는 다른 것이 있습니다.)

CNT=0

 cat input.data | ( while read 
do
  let CNT++;
  echo "Counting to $CNT"
done 
echo "Count is $CNT" )

긴 설명 :

  1. CNT스크립트에서 값 0으로 선언 합니다.
  2. SubShell은에서 시작 |됩니다 while read.
  3. 귀하의 $CNT변수는 값이 0 인 서브 쉘에 수출되고;
  4. SubShell은 CNT값을 세고 5로 증가시킵니다 .
  5. SubShell은 변수와 값이 소멸됩니다 (호출 프로세스 / 스크립트로 돌아 가지 않음).
  6. 당신은 당신 echo의 원래 CNT값 0입니다.

답변

이 작동합니다

CNT=0 

while read ;
do
  let CNT++;
  echo "Counting to $CNT"
done <input.data
echo "Count is $CNT"

답변

while 루프 이전의 파일처럼 하위 셸에서 데이터를 대신 전달하십시오. 이것은 lain의 솔루션과 유사하지만 간헐적 인 파일을 원하지 않는다고 가정합니다.

total=0
while read var
do
  echo "variable: $var"
  ((total+=var))
done < <(echo 45) #output from a command, script, or function
echo "total: $total"