리디렉션 루프를 만드는 방법

리디렉션 루프를 만드는 방법

이는 주로 학문적인 이유 때문입니다. ;-)

다음 Bash 문을 고려해보세요.

foo | bar

이는 두 프로세스를 모두 실행 foo하고 bar표준 출력이 foo표준 입력에 연결되도록 합니다 bar. 여태까지는 그런대로 잘됐다.

우리가 호출할 수 foo있는 메소드가 있나요?bar반품반대 방향으로 연결이 되어 있나요?

foo.stdout -> bar.stdin
foo.stdin  <- bar.stdout

내가 이해한 바에 따르면 Bash 호출은 상호 연결된 FD 쌍을 생성한 다음 해당 하위 프로세스에서 /를 pipe(2)대체하는 데 사용할 수 있습니다 . 커널 수준에서는 두 번 호출할 수 없을 이유가 없으며 위에서 설명한 순환 배열을 배열합니다.stdinstdoutpipe(2)

하지만 실제로 쉘 구문을 알아낼 수는 없습니다.하다저것.

지금까지 내가 떠올릴 수 있는 가장 좋은 아이디어는 명명된 파이프를 사용하거나 서브셸을 시작하고 어떻게든 미친 FD에서 FD로 리디렉션을 수행하는 것입니다...

답변1

Bash에서는 다음을 사용할 수 있습니다.공생(bash는 여러 coproc을 제대로 지원하지 않지만 여기서는 하나만 필요합니다):

#!/bin/bash
set -e
coproc { while read -r line; do echo "$BASHPID read: $line";  done; }
i=0; while :; do
    echo "$BASHPID writing>> $i"
    echo $i >&"${COPROC[1]}"
    read -r line <&"${COPROC[0]}"
    echo "$BASHPID coproc produced>> $line"
    i=$((i+1))
done

또는명명된 파이프(간단한 POSIX 셸에서도 작동합니다):

#!/bin/bash
set -e
trap 'rm -rf "$tmpd"' EXIT
tmpd=$(mktemp -d)

mkfifo "$tmpd/p0" "$tmpd/p1"
exec 3<>"$tmpd/p0"
exec 4<>"$tmpd/p1"
rm -rf "$tmpd"

( while read -r line; do echo "$BASHPID read: $line";  done; ) <&3 >&4  &
i=0; while :; do
    echo "$BASHPID writing>> $i" 
    echo $i >&3
    read -r line <&4
    echo "$BASHPID coproc produced>> $line"
    i=$((i+1))
done 

쉘에서 fd를 다루는 데 익숙하지 않다면, 모두 보기 흉해 보일 수 있습니다.

또한 스케줄링에 대한 파이프의 영향으로 인해(빈 파이프 버퍼가 있는 파이프에서 읽는 것과 마찬가지로 전체 파이프 버퍼가 있는 파이프에 쓰면 차단됨) 특정 읽기/쓰기 패턴이 갇힐 수 있습니다. 이중 자물쇠.

위 두 예제의 출력은 다음과 같습니다.

32435 writing>> 0
32435 coproc produced>> 32441 read: 0
32435 writing>> 1
32435 coproc produced>> 32441 read: 1
32435 writing>> 2
32435 coproc produced>> 32441 read: 2
32435 writing>> 3
32435 coproc produced>> 32441 read: 3
32435 writing>> 4
32435 coproc produced>> 32441 read: 4

답변2

Pipes()로는 이 작업을 수행할 수 없을 것 같지만 |서로 쓰고 읽는 비동기 프로세스를 사용하면 쉽습니다.

ksh93스크립트(bash추가 다운 버전) 두 개의 while루프를 시작하고, 그 사이에 숫자를 던지고, 각 트랜잭션의 숫자에 1을 추가합니다.

while read data; do
    print $(( data + 1 ))
done |&

print -p 1

while read -p data; do
    print $(( data + 1 ))
done >&p
  1. 첫 번째 루프는 공동 프로세스로 시작됩니다. 그것에 대한 입력을 기다립니다 read.
  2. 이 번호는 전체 프로세스를 시작하기 위해 공동 프로세스 1에 제공됩니다 .read
  3. 두 번째 루프는 첫 번째 루프와 동일한 작업을 시작하지만 공동 프로세스는 아닙니다.

활성화된 상태로 실행합니다 xtrace(수정된 스크립트를 사용하여 PS4추적 힌트를 "& "첫 번째 루프로 설정하고 "> "두 번째 루프를 로 설정하여 진행 상황을 표시합니다).

$ ksh -x script.sh
& PS4='& '
> PS4='> '
> print -p 1
> 1>& p
> read -p data
& read data
& print 2
& read data
> print 3
> read -p data
& print 4
> print 5
> read -p data
& read data
& print 6
& read data
> print 7
> read -p data
(etc.)

bash또한 공동 처리( coproc내장 검색)도 수행하지만 이에 대해 잘 알지 못합니다. 공동 처리 없이 셸에서 이 작업을 수행할 수도 있습니다.

편집하다: 이 같은 bash:

coproc while read data; do
    echo $(( data + 1 ))
done

echo 1 >&${COPROC[1]}

while read -u ${COPROC[0]} data; do
    echo $(( data + 1 ))
done >&${COPROC[1]}

실행하세요(위와 같이 수정된 추적 프롬프트를 사용하여):

$ bash -x script.sh
+ PS4='& '
& PS4='> '
> echo 1
> read -u 63 data
& read data
& echo 2
> echo 3
> read -u 63 data
& read data
& echo 4
> echo 5
> read -u 63 data
& read data
& echo 6
> echo 7
> read -u 63 data
(etc.)

답변3

보다 복잡한 파일 설명자 리디렉션 트리의 경우파이프라인 액츄에이터, 이는데비안 저장소.

실제로 이는 BASH 및 Bourne 유사 쉘의 구문 제한인 경우가 많습니다.

관련 정보