Mac의 zsh 5.9에서 이상한 동작이 관찰되었습니다. (다음은 오류를 재현하기 위해 단순화한 것으로, 이해가 되지 않습니다.) 터미널에서 실행하면
$> function assigner() { OPTIONS=mutated }
$> function main() { typeset OPTIONS; assigner; echo $OPTIONS }
$> main
이 출력은 다음과 같습니다.
mutated
하지만 내부 함수 호출의 출력을 리디렉션하기 위해 기본 함수를 미묘하게 변경하면...
$> function main() { typeset OPTIONS; assigner | cat; echo $OPTIONS }
그러면 결과가 비어 있습니다
내 OPTIONS var가 더 이상 채워지지 않습니다. 여기서 무슨 일이 일어나고 있는 걸까요?
답변1
파이프는 프로세스 간 통신 메커니즘입니다.
A | B
파이프라인 에서 A
표준 입력으로 파이프된 표준 출력과 병렬로 B
실행됩니다 .A
B
따라서 별도의 프로세스에서 실행되어야 합니다. 대부분의 셸에서는 하위 프로세스에서 실행됩니다. ksh의 원래 구현과 마찬가지로 zsh에서는 A
하위 프로세스에서만 실행됩니다(물론 B
외부 명령인 경우에도 여전히 하위 프로세스에서 실행됩니다).
따라서 하위 쉘 프로세스에서 실행 assigner | cat
되므로 assigner
상위 쉘 프로세스의 변수가 아닌 해당 하위 쉘의 변수만 수정합니다. 파이프라인이 종료되면 변수 변경 사항이 손실됩니다.
assigner
여기에서 상위 프로세스에서 실행 하고 싶지만 해당 출력을 cat
별도의 프로세스 로 파이프하는 경우 assigner
대신 출력을 실행 중인 프로세스로 리디렉션 할 수 있습니다 cat
.
assigner > >(cat)
cat
또는 보조 프로세스로 실행합니다.
코프로세스는 stdin 및 stdout을 파이프로 리디렉션하므로 기본 프로세스는 데이터를 공급하고 날짜를 가져올 수 있지만 추가 파일 설명자를 사용하여 원본 stdout을 저장하고 복원하면 stdout 부분을 제거할 수 있습니다.
assigner() OPTIONS=mutated
{ coproc cat >&3 3>&-; } 3>&1 # start cat as coproc with stdout restored
cat_pid=$! # record its pid
assigner >&p # run assigner with stdout redirected to coproc
coproc : # dummy coproc to close the pipes to the
# previous one.
wait $cat_pid # make sure cat has returned before running
# the next commands.
echo $OPTIONS
(바라보다다양한 쉘에서 coproc 명령을 사용하는 방법은 무엇입니까?코프로세스 사용 방법에 대한 자세한 내용)
또는 assigner
별도의 fd를 사용하고 실행 중인 동일한 하위 쉘에 설정된 변수를 사용하여 원시 stdout을 다시 사용 가능하게 만들 수 있습니다.
assigner() OPTIONS=mutated
{
{
assigner
echo $OPTIONS >&3
} | cat
} 3>&1