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및 명령은 cmd4동일한 범위에서 실행되는 반면, 명령 cmd2cmd3에는 각각 자체 하위 쉘이 지정되어 결과적으로 다른 범위가 지정되도록 해석됩니다. 원래 쉘은 두 하위 쉘의 상위입니다.

답변1

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

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

이 구문에서는 뒤에 공백이 있어야 하고 앞에는 { a (세미콜론)가 있어야 합니다 . 또한 필요하지 않습니다. 첫 번째 줄만 읽습니다.;}-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)

글쎄요, 정확히는 아닙니다. 첫 번째는 headbash내장 파이프입니다 read. 한 프로세스의 stdout을 다른 프로세스의 stdin으로 보냅니다.

두 번째 설명은 리디렉션 및 프로세스 대체입니다. 자체적 으로 처리됩니다 bash. 의 출력이 연결된 FIFO(Named Pipe <(...)) 를 생성하고 이를 프로세스로 리디렉션( ) 합니다 .head<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하위 쉘에서 실행된다는 것입니다.

한 가지 대답은heredoc:

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

이 방법은 POSIX와 유사한 쉘에서 동일한 방식으로 작동한다는 점에서 좋습니다.

관련 정보