필요한 작업을 자주 수행하고 싶습니다.
stdout
파이프라인(파이프라고 함)을pipeline-before
두 개의 병렬 스트림으로 분할합니다.- 결과 스트림(
stdin
)을 두 개의 개별 파이프(pipeline-between-0
및pipeline-between-1
)에 공급합니다. - 두 개의 결과
stdout
스트림 병합엄격한 순서로; - 병합된 결과 스트림을
stdin
다른 파이프(pipeline-after
)에 공급합니다.
(3)에서 "엄격한 순서로"는 의 모든 출력이 의 pipeline-between-0
출력보다 먼저 병합된 출력 스트림에 나타나야 함 을 의미합니다 pipeline-between-1
.
모든 것을 그래픽으로 표현할 수 있습니다.
pipeline-before --.--- pipeline-between-0 -.
\ \
`- pipeline-between-1 ---`-- pipeline-after
pipeline-between-0
이러한/쌍의 예는 pipeline-between-1
다음과 같습니다.
head -n 1 | tr 'a-z' 'A-Z'
tail -n +2 | sort -t $'\t' -k1,1
영어에서는 이 조합을 "첫 번째 행을 모두 대문자로 만들고 나머지 행을 첫 번째 열로 정렬하는 것"이라고 설명합니다.
묻다:그러한 작업을 표현하기 위한 일반적인 쉘 구문이 있습니까?
나는 이 질문에 대한 답변에 관심이 있습니다 zsh
.bash
일반적으로 말하면 이것은 구문입니다.아니요일하다:
$ pipeline-before | tee >( pipeline-between-0 ) | pipeline-between-1 | pipeline-after
이 구문은 다음 두 가지 이유로 실패합니다.
- 의 일부 출력이
pipeline-between-1
의 일부 출력 앞에 나타나는 경우가 많습니다pipeline-between-0
. SIGPIPE
결국 출력이 잘립니다( 신호 때문인 것으로 의심됩니다 ).
나는 다음을 시도했다운동(나는 100% 이해하지 못한다는 것을 인정합니다):
{
pipeline-before |
{ tee >( pipeline-between-0 4>&1 1>&3 ); } |
pipeline-between-1
} 3>&1 | pipeline-after
AFAICT, 이 구문은 위에 나열된 첫 번째 문제를 해결하는 것으로 보입니다(즉, 일부 비공식 테스트를 기반으로 의 pipeline-between-0
출력이 pipeline-between-1
올바른 순서로 나타남). 그러나 불행히도 적어도 어떤 경우에는 최종 출력이 여전히 잘립니다.
답변1
어쩌면 명명된 파이프(FIFO)만 필요할 수도 있습니다.
아래 예:
{ seq 1 100000 | grep 1$ & seq 1 100000 | grep 2$ ; } > unsorted
파일에서 1과 2로 끝나는 숫자의 혼합이 반환되어야 합니다 unsorted
. 우리는 그것들이 정렬되기를 원하므로(모든 숫자는 1로 끝나고 모든 숫자는 2로 끝남) 이제 각 결과에 하나씩 두 개의 명명된 파이프를 만들고 원하는 순서로 결합합니다.
mkfifo stream{1,2}
{ seq 1 100000 | grep 1$ >stream1 & seq 1 100000 | grep 2$ > stream2 ; } &\
cat stream1 stream2 > sorted
파일의 순서가 동일한지 확인하세요.
diff -q {un,}sorted
(그들은 달라야 합니다) 정렬된 순서가 예상대로인지 확인합니다.
sed 1,10000q sorted | grep 2$
(결과가 없어야 하며 unsorted
파일은 데이터를 반환해야 합니다)
bash
명명된 파이프는 에서도 동일하게 작동해야 합니다 zsh
.
또는 의사코드의 가장 일반적인 표현은 다음과 같습니다.
tee
입력 스트림("파이프 전")은 FIFO를 통해 여러 병렬 스트림으로 복사됩니다in-i
.- 각 스트림은 서로 다른 명령에 의해 병렬로 처리되고 해당 출력은 스트림
out-i
("i 사이의 파이프")으로 전송됩니다. - 원하는 순서로 출력 스트림을 연결하고 다음 명령("애프터 파이프")으로 전달합니다.
mkfifo {in,out}-{0..n}
pre-cmd | tee in-0 in-1 ... in-n | cat >/dev/null &
cmd-0 <in-0 >out-0 &
cmd-1 <in-0 >out-0 &
....
cmd-i <in-n >out-n &
cat out-0 out-1 ... out-n | after-cmd
나는 일반화의 이유로 cat >/dev/null
대신 사용하고 있습니다. 동일한 내용 은 (아마도) 궁극적으로 중복됩니다.cat >in-n
cat
예:
mkfifo {in,out}-{0..2}
seq 0 100 | tee in-{0..2} | cat >/dev/null &
grep '33$' <in-0 >out-0 &
awk '$1<2' <in-1 >out-1 &
sed '/^.\{1,2\}$/d' <in-2 >out-2 &
cat out-2 out-0 out-1 | tr '\n' '-'
결과:100-33-0-1-
답변2
당신은 그것을 찾고 있습니까 parallel --tee
? 출력을 위한 충분한 여유 디스크 공간이 있는 한 /tmp
모든 크기의 입력을 쉽게 처리할 수 있습니다 .
(printf "Header1\tHeader2\n"; paste <(seq 20 -1 11) <(seq 10) ) |
parallel -k --pipe --tee ::: "head -n 1 | tr 'a-z' 'A-Z'" "tail -n +2 | sort -t $'\t' -k1,1"
또는 bash 기능과 동일합니다.
pipeline-before() {
printf "Header1\tHeader2\n"
paste <(seq 20 -1 11) <(seq 10)
}
pipeline-between-0() {
head -n 1 | tr 'a-z' 'A-Z'
}
pipeline-between-1() {
tail -n +2 | sort -t $'\t' -k1,1
}
pipeline-after() {
echo "This is pipeline-after"
cat
echo "Done"
}
export -f pipeline-before pipeline-between-0 pipeline-between-1 pipeline-after
pipeline-before |
parallel -k --pipe --tee ::: pipeline-between-0 pipeline-between-1 |
pipeline-after
그렇지 않다면 더 많은 입력, 출력 및 파이프라인-*이 무엇인지에 대한 예를 자세히 설명할 수 있습니까?