나는 다음과 같은 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
변수를 사용하는 부분이 새로운 명령어 집합이기 때문이다. 대신 이것을 사용하십시오:
head somefile | { read A B C D E FOO; echo $A $B $C $D $E $FOO; }
이 구문에서는 뒤에 공백이 있어야 하고 앞에는 {
(세미콜론)이 있어야 합니다. 꼭 필요한 것은 아닙니다. 첫 번째 줄만 읽습니다.;
}
-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
. 한 프로세스의 표준 출력은 다른 프로세스의 표준 입력으로 이동됩니다.
두 번째 설명은 리디렉션 및 프로세스 교체입니다. 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와 유사한 셸에서 동일한 방식으로 작동하기 때문에 좋습니다.