while 루프 후에 배열이 비어 있는 이유는 무엇입니까? [복사]

while 루프 후에 배열이 비어 있는 이유는 무엇입니까? [복사]

다음과 같은 방법으로 bash-4.2에서 배열을 초기화하려고 합니다.

ring=()
ls -las | tail -n +4 | while read line
> do
> ring+=("$line")
> echo ${ring[-1]}
> done
3924 -rw-r--r-- 1 username group 4015716 Mar 23 15:14 script.jar
4 -rw-r--r-- 1 username group 9 Feb 29 12:40 rec.lst
5541 -rw-r--r-- 1 username group 5674226917 Mar 28 15:25 debug.out
8 -rw-r--r-- 1 username group 6135 Mar 25 12:16 script.class
8 -rw-r--r-- 1 username group 6377 Mar 25 11:57 script.java
8 -rwxr-xr-x 1 username group 4930 Mar 8 15:21 script-0.0.0.sh
8 -rwxr-xr-x 1 username group 6361 Mar 28 15:27 script-0.0.1.sh
echo ${ring[0]}

echo "${ring[0]}"

echo "${ring[@]}"

무엇이 잘못되었으며 루프가 끝난 후 빈 배열이 나타나는 이유는 무엇입니까?

답변1

문제는 파이프( command1 | command2 | command3 ...)에서 명령이 하위 쉘에서 실행된다는 것입니다. 변수는 서브쉘 간이나 서브쉘과 메인 쉘 간에 공유되지 않습니다. while 루프 내부의 루프는 ring기본 셸의 루프와 다릅니다.ring

이 문제를 극복하는 한 가지 방법은 프로세스 대체를 사용하는 것입니다.

while read line;  do  ring+=("$line");  echo ${ring[-1]};  done < <(ls -las|tail -n +4) 

문법 <(command)이라고 합니다프로세스 교체명령의 출력을 명명된 파이프로 리디렉션합니다. 그런 다음 <마치 파일인 것처럼 익숙한 파일로 리디렉션됩니다 . 를 사용하면 <서브쉘이 없으므로 ring이 변수가 설정됩니다.

파일의 줄에서 배열을 채우는 쉘이 내장되어 있습니다.

mapfile -t ring < <(ls -las | tail -n +4)

답변2

이것은 잘 작동합니다:

ring=()
while read line
do
ring+=("$line")
echo ${ring[-1]}
done < <(ls -las | tail -n +4)

원천:http://wiki.bash-hackers.org/syntax/arrays

답변3

그 이유는 while 루프가 파이프로 연결되어 있기 때문에 서브셸에서 실행되기 때문입니다. 서브쉘은 상위 쉘 환경의 사본을 사용하며 서브쉘이 종료될 때 이를 다시 전달하지 않습니다.

Bash의 경우 명령 그룹화 해결 방법을 사용할 수 있습니다. 추가된 중괄호에 유의하세요.

ls -las | tail -n +4 | { while read line;  do  ring+=("$line");  echo ${ring[-1]};  done;  echo ${ring[0]}; }

관련 정보