대시: 파이프에서 변수 읽기

대시: 파이프에서 변수 읽기

bash또는 에서는 zsh다음 구문을 사용하여 파이프에서 변수를 읽을 수 있습니다.

echo AAA BBB | read X Y ; echo $X

이것은 인쇄됩니다AAA

에서 동일한 접근 방식이 작동하지 않는 이유는 무엇입니까 /bin/sh?

사용하고 있어요 /bin/sh->/bin/dash 스프린트데비안에서

답변1

왜 같은 방법이 '/bin/sh'에서 작동하지 않습니까?

파이프라인의 각 명령이 하위 셸에서 실행되기 때문에 파이프라인에서 변수를 할당하면 예상대로 sh작동 하지 않습니다. bash실제로 명령은실제로 작동한다가 선언 X되었지만 Y파이프라인 외부에서는 사용할 수 없습니다.

다음이 작동합니다:

echo AAA BBB | { read X Y ; echo $X; }

하지만 귀하의 경우에는:

이 시도,

read X Y <<< "AAA BBB"

또는

read X Y < <(echo "AAA BBB")

유용한 링크:

답변2

Bash 또는 zsh에서는 다음 구문을 사용하여 파이프에서 변수를 읽을 수 있습니다.

echo AAA BBB | read X Y ; echo $X

아니 당신은 할 수 없습니다. 기본적으로 Bash에서는 사용할 수 없습니다.

$ ./bash5.0-alpha -c 'echo AAA BBB | read X Y ; echo "Bash=$BASH_VERSION X=\"$X\""'
Bash=5.0.0(1)-alpha X=""
$ bash -c 'echo AAA BBB | read X Y ; echo "Bash=$BASH_VERSION X=\"$X\""'
Bash=4.4.12(1)-release X=""

Bash는 별도의 하위 셸 환경에서 파이프라인의 모든 명령을 실행하므로 셸 변수에 대한 변경 사항은 파이프라인 외부에 표시되지 않습니다. 대시도 여기와 비슷합니다.

Zsh 및 ksh(AT&T 구현 pdksh또는 그 파생물 아님)는 기본 셸 환경에서 파이프라인의 마지막 명령을 실행하므로 다음과 같이 작동합니다.

$ zsh -c 'echo AAA BBB | read X Y ; echo "Zsh=$ZSH_VERSION X=\"$X\""'
Zsh=5.3.1 X="AAA"

Bash에서는 shopt -s lastpipeksh 및 zsh가 수행하는 작업을 수행하도록 할 수 있습니다(단, 비대화형 쉘에만 해당).

$ bash -O lastpipe -c 'echo AAA BBB | read X Y ; echo "Bash=$BASH_VERSION X=\"$X\""'
Bash=4.4.12(1)-release X="AAA"

하지만 대시에는 그런 선택권이 없다고 생각합니다.

Bash에서는 파이프 대신 프로세스 대체를 사용할 수도 있지만 이는 Dash에서도 옵션이 아닙니다.


해결책은 루프의 오른쪽을 복합 명령문이나 함수로 만들어 파이프에서 읽은 값을 읽은 것과 동일한 컨텍스트에서 사용하는 것입니다.

$ dash -c 'echo AAA BBB | { read X Y ; echo "X=\"$X\""; } '
X="AAA"
$ dash -c 'f() { read X Y ; echo "X=\"$X\""; }; echo AAA BBB | f'
X="AAA"

또는 여기 문서를 사용하세요.

read X Y << EOF
$(echo AAA BBB)
EOF

답변3

아니요, X와 Y(세미콜론 뒤)는 설정되지 않습니다.

echo AAA BBB | read X Y ; echo $X
$ bash -c 'echo AAA BBB | read X Y ; echo "<$X>"'
<>

대시에서도 같은 일이 발생합니다.

대시보드에서 작동하게 하려면 이전 솔루션(여기 문서)을 사용해야 합니다.

$ read X Y <<_EOT_
> AAA BBB
> _EOT_
$ echo "<$X>"
<AAA>

쉘을 시도하기 위한 명령으로(안타깝게도 개행 문자는 제거할 수 없습니다(한 줄 문자 없음)):

$ bash -c 'read X Y <<_EOT_
AAA BBB
_EOT_
echo "<$X>" '
<AAA>

이는 dash, zsh, ksh 및 기타 여러 도구에서 정확히 동일하게 작동합니다.

$ dash -c 'read X Y <<_EOT_
AAA BBB
_EOT_
echo "<$X>" '
<AAA>

새로운 대안(대시에서는 작동하지 않음)은 다음 here-doc과 같습니다.

  1. 문자열은 다음과 같습니다(bash, ksh, zsh용).

    $ bash -c 'read X Y <<<"AAA BBB"; echo "<$X>" '
    <AAA>
    
  2. 프로세스 교체(bash, ksh, zsh에 적용 가능):

    $ bash -c 'read X Y < <(echo AAA BBB) ; echo "<$X>" '
    <AAA>
    

값을 인쇄하고 대시로 작업하는 또 다른 대안은 다음과 같습니다.

  1. 그룹 명령:

    $ dash -c 'echo "AAA BBB" | { read X Y ; echo "<$X>"; }; echo "<$X>" '
    <AAA>
    <>
    

    마지막 솔루션은 bash에 설정된 변수 lastpipe(대화식 사용이 아님) 또는 ksh/zsh의 기본 설정을 유지하도록 설정할 수 있습니다.

    $ bash -c 'shopt -s lastpipe;echo "AAA BBB"|{ read X Y;echo "1<$X>"; };echo "2<$X>"'
    1<AAA>
    2<AAA>
    
    $ ksh -c 'echo "AAA BBB"|{ read X Y;echo "1<$X>"; };echo "2<$X>"'
    1<AAA>
    2<AAA>
    
    $ zsh -c 'echo "AAA BBB"|{ read X Y;echo "1<$X>"; }; echo "2<$X>"'
    1<AAA>
    2<AAA>
    

답변4

파이프의 프로세스별 변수 할당에 주의하세요. POSIX 표준은 특정 동작을 요구하지 않습니다.

최신 셸 ksh93과 최신 버전의 셸은 Bourne Shell기본 셸을 파이프라인에 있는 두 프로세스의 상위 프로세스로 만들고, 가장 오른쪽 프로세스가 내장 명령인 경우 해당 명령은 기본 셸에서도 실행됩니다.

또 다른 변형은 위의 방법을 사용하지만 항상 다른 프로세스에서 가장 오른쪽 명령을 실행하는 것입니다.

이전 버전은 원래 Bourne Shell이 ​​작동하는 방식입니다. 쉘 포크, 포크 프로세스는 파이프에서 다른 모든 프로세스를 생성하고 결국 가장 오른쪽 프로세스로 전환합니다.

마지막 버전은 다른 버전보다 훨씬 적은 코드가 필요하지만 속도가 느립니다. 코드 크기 문제로 인해 1976년에 사용되었습니다.

첫 번째 변형은 가장 빠르지만 다른 변형보다 더 많은 코드가 필요하지만 원래 셸 프로세스에서 변수 할당을 실행하는 유일한 변형이므로 수정된 변수 값이 기본 셸에 있어야 합니다.

관련 정보