간단한 테스트 케이스가 있습니다
local testa=("a")
local testb=("b")
function test { testb=(${(P)1}) }
test "testa"
echo "testb="$testb
출력 testb=a
및
local testa=("a")
local testb=("b")
function test { testb=(${(P)1}) }
test "testa" | cat
echo "testb="$testb
출력은 다음과 같습니다testb=b
나는 동일한 결과가 출력에 적용되어야 한다고 가정합니다 testb=a
.
뭐가 문제 야?
답변1
파이프는 변수 변경 사항이 상위 셸에서 가려지는 하위 셸을 도입합니다.while
루프 내의 변수 변경이 상위 항목에 영향을 주지 않는 파이프를 포함하는 루프. 모듈을 통해 PID 변경을 관찰할 수 있습니다 zsh/system
.
zmodload zsh/system
local testa=("a")
local testb=("b")
function test {
testb=(${(P)1})
echo "INSIDE testb=$testb $sysparams[pid]"
}
test "testa" | cat
echo "OUTSIDE testb=$testb $sysparams[pid]"
다음과 같이 표시되어야합니다
% zsh foo.zsh
INSIDE testb=a 61488
OUTSIDE testb=b 61487
%
다른 서브쉘, 다른 변수.
답변2
파이프 오퍼레이터의 양쪽이 평행하게 움직입니다. 이는 별도의 프로세스에서 양쪽을 실행하여 수행됩니다. (이것은 원래 Unix 셸에서 이 작업을 수행하는 유일한 방법이었으며 현대 셸에서도 이 작업을 수행하는 유일한 방법입니다.) 다음 코드 조각을 고려하세요.
testb=left | testb=right
echo $testb
zsh에서 파이프 연산자의 오른쪽은 원래 프로세스에서 실행되고 왼쪽은 다음에서 실행됩니다.서브쉘. 하위 쉘은 일반적으로 별도의 프로세스를 통해 구현됩니다. 쉘이 실행을 최적화하고 별도의 프로세스를 사용하지 않더라도 쉘 상태(변수, 리디렉션 등)에 대한 모든 수정이 하위 쉘로 제한되므로 일관성이 유지됩니다. . 따라서 위의 코드 조각이 인쇄됩니다 right
.
(다른 쉘도 서브쉘에서 파이프의 오른쪽을 실행할 수 있습니다. 일반적인 쉘 중 zsh 및 ATT ksh만 원래 컨텍스트에서 오른쪽을 실행합니다. 왼쪽은 항상 서브쉘에서 실행됩니다.)
하위 쉘을 생성하지 않고 데이터를 파이프하려면 다음을 사용할 수 있습니다.프로세스 교체. 프로세스 대체는 서브셸에 파이프를 생성하고 원래 컨텍스트가 파이프의 입력 또는 출력에 연결되는지 여부를 제어합니다.
test "testa" > >(cat)
>
( >(…)
와 : 사이의 공백은 >>(cat)
추가 모드에서 프로세스 대체로 구문 분석되어 파이프 경로를 두 번째 인수로 전달합니다 test
. 여기서는 함수 호출의 출력을 파이프로 리디렉션하려고 합니다.)