파이프를 사용할 때 읽기 명령을 서브셸에 넣어야 하는 이유는 무엇입니까?

파이프를 사용할 때 읽기 명령을 서브셸에 넣어야 하는 이유는 무엇입니까?

이 명령은 df .현재 사용 중인 장치를 표시합니다. 예를 들어,

me@ubuntu1804:~$ df .
Filesystem     1K-blocks    Used Available Use% Mounted on
/dev/sdb1       61664044 8510340  49991644  15% /home

이제 문자열을 얻고 싶습니다 /dev/sdb1.

이 작업을 시도했지만 작동하지 않습니다. df . | read a; read a b; echo "$a"이 명령은 빈 출력을 제공합니다. 하지만 df . | (read a; read a b; echo "$a")예상대로 작동합니다.

지금은 조금 혼란스러워요.

이것이 서브쉘이라는 것은 알지만 (read a; read a b; echo "$a")왜 여기서 서브쉘을 만들어야 하는지 모르겠습니다. 내가 이해하는 바에 따르면 의 출력은 의 입력으로 x|y리디렉션됩니다 . 왜 나는 입력을 받을 수 없는데 서브셸에서는 입력을 받을 수 있나요?xyread a; read a b; echo $a

답변1

여기서 가장 중요한 문제는 명령을 올바르게 그룹화하는 것입니다. 서브쉘은 사소한 문제입니다.

x|yx출력을 입력으로 리디렉션y

예, 하지만 출력을 에서 또는 으로 x | y; z리디렉션하지 않습니다 .xyz

에서는 df . | read a; read a b; echo "$a"파이프가 연결만 되고 df .다른 read a명령은 이 파이프와 연결되지 않습니다. read그것들을 함께 그룹화 df . | { read a; read a b; }하거나 df . | (read a; read a b)파이프를 연결 해야 합니다 .

그러나 이제 하위 셸 문제가 발생했습니다. 파이프라인의 명령이 하위 셸에서 실행되므로 하위 셸에 변수를 설정해도 상위 셸에 영향을 주지 않습니다. 따라서 이 echo명령은 reads와 동일한 하위 쉘에 있어야 합니다. 그래서: df . | { read a; read a b; echo "$a"; }.

이제 파이프의 명령은 어쨌든 서브셸에서 실행되므로 사용 여부 ( ... )에 특별한 차이가 없습니다 .{ ...; }

답변2

또 다른 방법은프로세스 교체:

{ read header; read filesystem rest; } < <(df .)
echo "$filesystem"

프로세스 교체는 포함된 스크립트(하위 쉘에 있음)를 실행하지만 파일 이름처럼 작동하므로 먼저 내용(즉, 스크립트의 출력)을 중괄호 스크립트로 리디렉션 <(...)해야 합니다 . <그룹화된 명령은 현재 쉘에서 실행됩니다.

읽기 쉽게 만드는 것은 어려울 수 있지만 중괄호와 절차적 대체에 임의의 공백을 넣을 수 있습니다.

{
    read header
    read filesystem rest
} < <(
    df .
)
echo "$filesystem"

외부 도구를 사용하여 파일 시스템을 추출하는 것이 더 쉬울 수 있습니다.

filesystem=$( df . | awk 'NR == 2 {print $1}' )

답변3

첫 번째 명령

df . | read a; read a b; echo "$a"

실제로는 다음과 같이 해석된다.

( df . | read a ) ; read a b; echo "$a"

따라서 파이프는 read a명령만 입력합니다.

파이프에서 여러 번 읽기를 원하므로 명령을 그룹화해야 합니다.

이제 서브쉘일 필요는 없습니다. 단체일수도..

bash-4.2$ df | { read a ; read a b ; echo $a ; }
devtmpfs

더 일반적으로 루프가 필요할 수 있습니다.

bash-4.2$ df | while read a
> do
> read a b
> echo $a
> done
devtmpfs
tmpfs
/dev/vda3
/dev/vdb

bash파이프 오른쪽이 서브쉘을 실행하고 있어서 루프 외부에서는 값에 접근 $a $b할 수 없다는 사소한 문제도 있지만 while그건 다른 문제입니다!

관련 정보