22장. 프로세스 치환(Process Substitution)

프로세스 치환명령어 치환과 짝을 이루는 개념입니다. 명령어 치환은 dir_contents=`ls -al` 이나 xref=$(grep word datafile) 처럼 명령어의 결과를 어떤 변수의 값으로 설정해 줍니다. 프로세스 치환은 프로세스의 출력을 다른 프로세스에게 넣어 줍니다(다른 말로 하면, 한 명령어의 결과를 다른 명령어에게 전달합니다).

명령어 치환 템플릿

소괄호에 들어 있는 명령어

>(command)

<(command)

이런 식으로 프로세스 치환을 초기화하는데, /dev/fd/<n> 이라고 해서 괄호안에 있는 프로세스의 결과를 다른 프로세스에게 전달해 줍니다. [1]

참고: "<"">" 와 소괄호 사이에는 빈 칸이 들어 가지 않습니다. 빈 칸이 들어가면 에러 메세지가 나옵니다.

bash$ echo >(true)
/dev/fd/63

bash$ echo <(true)
/dev/fd/63
	      
Bash는 파이프를 만들 때, --fInfOut--, 두 개의 파일 디스크립터를 씁니다. true의 표준입력을 fOut(dup2(fOut, 0))으로 연결하고 나면, Bash가 /dev/fd/fIn 인자를 echo로 전달해 줍니다. /dev/fd/<n> 이 없는 시스템에서는 Bash가 임시 파일을 쓸 것입니다.(Thanks, S.C.)

cat <(ls -l)
# ls -l | cat 와 같습니다.

sort -k 9 <(ls -l /bin) <(ls -l /usr/bin) <(ls -l /usr/X11R6/bin)
# 3개의 중요한 'bin' 디렉토리안의 파일 목록들을 파일명 순으로 정렬해서 보여줍니다.
# 중요한 것은 3개의 구분된 명령어가 'sort'의 입력으로 들어가는 것입니다.


diff <(command1) <(command2)    # 명령어 출력에서 다른 점을 보여줍니다.

tar cf >(bzip2 -c > file.tar.bz2) dir
# "tar cf /dev/fd/?? dir" 를 부르고, "bzip2 -c > file.tar.bz2" 를 부릅니다.
#
# /dev/fd/<n> 가 시스템에 따른 특징이기 때문에 두 명령어 사이의
# 파이프가 네임드 파이프일 필요는 없습니다
#
# 위에서 했던 것을 이렇게 흉내를 내 보죠.
#
bzip2 -c < pipe > file.tar.bz2&
tar cf pipe dir
rm pipe
#        이렇게도 할 수 있겠네요.
exec 3>&1
tar cf /dev/fd/4 dir 4>&1 >&3 3>&- | bzip2 -c > file.tar.bz2 3>&-
exec 3>&-


# Thanks, S.C.

다음은 독자 한 분이 보내 주신 프로세스 치환에 대한 재밌는 예제입니다.

# SuSE 배포판의 스크립트 일부분을 인용:

while read  des what mask iface; do
# 명령어 몇 개...
done < <(route -n)


# 시험하기 위해서 몇 가지를 덧붙여 봅시다.
while read  des what mask iface; do
  echo $des $what $mask $iface
done < <(route -n)

# 출력:
# Kernel IP routing table
# Destination Gateway Genmask Flags Metric Ref Use Iface
# 127.0.0.0 0.0.0.0 255.0.0.0 U 0 0 0 lo


# S.C. 가 지적한 것처럼, 이해하기 쉽게 다시 쓰면:
route -n |
  while read des what mask iface; do   # 파이프 출력을 써서 변수를 세팅.
    echo $des $what $mask $iface
  done  # 위와 똑같은 결과를 보여줍니다.

주석

[1]

이렇게 하면 네임드 파이프(named pipe, 임시 파일)를 쓰는 것과 같고, 사실 프로세스 치환에서 네임드 파이프가 한 번 쓰입니다.