while 루프 없이 bash의 읽기 내장 명령 사용

while 루프 없이 bash의 읽기 내장 명령 사용

나는 다음과 같은 while 루프의 내장 함수에 익숙합니다 bash.read

echo "0 1
      1 1
      1 2
      2 3" |\
while read A B; do
    echo $A + $B | bc;
done

make나는 파일을 분할하고 중간 결과를 저장하는 것이 신중해진 일부 프로젝트를 진행해 왔습니다 . 따라서 단일 행을 변수로 나누는 경우가 많습니다. 아래 예제는 제대로 작동하지만,

head -n1 somefile | while read A B C D E FOO; do [... use vars here ...]; done

while 루프는 두 번 이상 실행되지 않기 때문에 이것은 약간 어리석은 일입니다. 하지만 그렇지 않다면 while,

head -n1 somefile | read A B C D E FOO; [... use vars here ...]

이를 사용할 때 읽은 변수는 항상 비어 있습니다. read나는 일반적으로 많은 유사한 행을 처리하기 위해 while 루프를 사용하기 때문에 이 동작을 본 적이 없습니다 . while 루프 없이 의 bash내장 함수를 어떻게 사용할 수 있습니까? read아니면 한 줄을 여러(!) 변수로 읽는 또 다른(더 나은) 방법이 있습니까?

결론적으로

대답은 이것이 범위 지정 문제임을 알려줍니다. 성명서

 cmd0; cmd1; cmd2 | cmd3; cmd4

명령 으로 해석되고 cmd0동일한 범위에서 실행되는 반면 명령 및 에는 cmd1각각 자체 하위 쉘이 제공되므로 범위가 다릅니다. 원래 쉘은 두 하위 쉘의 상위 쉘입니다.cmd4cmd2cmd3

답변1

변수를 사용하는 부분이 새로운 명령어 집합이기 때문이다. 대신 이것을 사용하십시오:

head somefile | { read A B C D E FOO; echo $A $B $C $D $E $FOO; }

이 구문에서는 뒤에 공백이 있어야 하고 앞에는 { (세미콜론)이 있어야 합니다. 꼭 필요한 것은 아닙니다. 첫 번째 줄만 읽습니다.;}-n1read

더 나은 이해를 위해 위와 동일한 작업을 수행하는 데 도움이 될 수 있습니다.

read A B C D E FOO < <(head somefile); echo $A $B $C $D $E $FOO

편집하다:

다음 두 진술은 동일한 효과를 갖는다고 흔히 말합니다.

head somefile | read A B C D E FOO
read A B C D E FOO < <(head somefile)

글쎄요, 정확히는 아닙니다. 첫 번째는 head에서 까지 의 bash내장 파이프 입니다 read. 한 프로세스의 표준 출력은 다른 프로세스의 표준 입력으로 이동됩니다.

두 번째 설명은 리디렉션 및 프로세스 교체입니다. bash자체적으로 처리 됩니다 . FIFO(파이프라는 이름 <(...)) 를 생성하고 head해당 출력을 FIFO에 연결한 다음 이를 프로세스 <로 리디렉션()합니다 .read

지금까지는 이것들이 동일해 보입니다. 그러나 변수를 사용할 때는 이것이 중요할 수 있습니다. 첫 번째에서는 실행 후 변수가 설정되지 않습니다. 두 번째에서는 현재 환경에서 사용할 수 있습니다.

이 상황에서는 각 쉘이 다르게 작동합니다. 바라보다그 링크그들은 이것을 위해 여기에 있습니다. 명령 그룹화, 프로세스 대체( ) 또는 여기에 문자열( )을 사용하여 bash이 동작을 해결할 수 있습니다.{}< <()<<<

답변2

매우 유용한 기사에서 인용wiki.bash-hackers.org:

이는 파이프된 명령이 상위 쉘을 수정할 수 없는 하위 쉘에서 실행되기 때문입니다. 따라서 상위 셸의 변수는 수정되지 않습니다(문서 참조:Bash 및 프로세스 트리).

답변이 여러 번 제공되었으므로 다른 방법(내장되지 않은 명령을 사용하여...)은 다음과 같습니다.

$ eval `echo 0 1 | awk '{print "A="$1";B="$2}'`;echo $B $A
$ 1 0

답변3

지적했듯이 문제는 파이프가 read하위 쉘에서 실행된다는 것입니다.

한 가지 대답은 다음을 사용하는 것입니다.트레독:

numbers="01 02"
read first second <<INPUT
$numbers
INPUT
echo $first
echo $second

이 접근 방식은 POSIX와 유사한 셸에서 동일한 방식으로 작동하기 때문에 좋습니다.

관련 정보