이 페이지함수 생성을 compose
위한 의사 코드가 자세히 설명되어 있습니다.N명령을 내리고 파이프라인에서 실행합니다.
compose
우리는 다음과 같은 명령을 작성합니다 .compose cmd1 cmd2 ... cmdn
이는 쉘 명령처럼 작동합니다.
cmd1 | cmd2 | ... | cmdn
나는 노력하고있다명명된 파이프저는 compose
실제로 Bash로 글을 쓰는 데 관심이 있습니다. 불행하게도 이 작업을 수행하면 출력이 전혀 나오지 않습니다. 아마도 다른 파이프에 대한 읽기 및 쓰기 경쟁 조건으로 인해 발생한 것 같습니다. 여러 번 반복했는데 계속 혼란스러운 동작이 발생합니다. 나는 그것을 이 작은 문제로 축소했습니다.
echo foo | # stdin
{
mkfifo p # create pipe p
cat > p & # direct stdin to pipe p
cat < p # read pipe p to stdout
rm p # remove pipe p
}
이 출력을 원 foo
하지만 아무것도 얻지 못합니다. 내가 뭘 잘못했나요?
답변1
질문에 있는 예제 코드의 문제는 미묘합니다. 명명된 파이프에 쓰려면 &
명령을 백그라운드에 두어야 합니다. 그렇지 않으면 읽기를 기다리는 것이 차단됩니다. 그런데 이렇게 하면 "백그라운드에서 시작된 명령은 &
표준 입력이 [to] 로 리디렉션됩니다 /dev/null
."는 표준 입력이 아닌 /dev/null
파이프를 통해 입력된 내용을 의미합니다.p
Bash에서 솔루션은 간단합니다. stdin을 백그라운드 프로세스로 리디렉션합니다 0<&0
. 그러면 예제가 제대로 작동할 것입니다.
$ echo foo | { mkfifo p; cat 0<&0 > p & cat < p; rm p; }
foo
전체 compose
함수는 다음과 같이 표시됩니다.
compose() {
dir=$(mktemp -d) # Create a temp dir to hold the pipes
cd $dir # to avoid filename conflicts
i=0 #
mkfifo "pipe$i" # Create pipe0, the output for command $1
($1 0<&0 > "pipe$i" &) # Start $1, reading stdin and writing to pipe0
shift # Shift off $1 since it's running
for c in "$@"; do # Loop over the remaining commands
ii=$((i+1)) #
mkfifo "pipe$ii" # Create a pipe i+1, the next command's output
($c < "pipe$i" > "pipe$ii" &) # Start the next command, reading from the
i=$ii # i'th pipe and writing to the i+1'th
done #
cat "pipe$i" # Output the last pipe, executing the commands
cd - > /dev/null # Change back to the old directory
rm -rf $dir # Remove all the pipes
}
답변2
compose()
case $# in
[01]) "$@" ;; ## if 1 or fewer args just run what we've got
*) "$1" | { ## otherwise pipe output from $1 into a
shift; compose "$@" ## self-call until all args are gone
}; esac