파이프라인 기능에서 zsh 할당이 실패합니다.

파이프라인 기능에서 zsh 할당이 실패합니다.

간단한 테스트 케이스가 있습니다

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. 여기서는 함수 호출의 출력을 파이프로 리디렉션하려고 합니다.)

관련 정보