나는 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
동일한 범위에서 실행되는 반면, 명령 cmd2
및 cmd3
에는 각각 자체 하위 쉘이 지정되어 결과적으로 다른 범위가 지정되도록 해석됩니다. 원래 쉘은 두 하위 쉘의 상위입니다.
답변1
vars를 사용하는 부분이 새로운 명령 집합이기 때문입니다. 대신 이것을 사용하십시오:
head somefile | { read A B C D E FOO; echo $A $B $C $D $E $FOO; }
이 구문에서는 뒤에 공백이 있어야 하고 앞에는 {
a (세미콜론)가 있어야 합니다 . 또한 필요하지 않습니다. 첫 번째 줄만 읽습니다.;
}
-n1
read
더 나은 이해를 위해 이것이 도움이 될 수 있습니다. 위와 동일합니다.
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
. 한 프로세스의 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와 유사한 쉘에서 동일한 방식으로 작동한다는 점에서 좋습니다.