다른 두 명령의 출력을 통해 명령을 파이프한 다음 두 프로세스 대체 결과를 병합하려고 합니다. 나를 가깝게 만든 예는 다음과 같습니다.
command | tee >(sed -rn 's/.*foo (bar).*/1/p') >(awk '{print $3}')
그러나 나는 다음과 같은 목표를 달성하고 싶다.
- 원래 명령의 입력 스트림을 볼 필요가 없습니다.
- "붙여넣기"를 사용하여 결과를 병합하고 싶습니다.
한 가지 옵션은 두 개의 개별 명령을 실행하여 파일에 저장하는 것이지만 원하는 만큼 우아하지는 않습니다. Bash에서 이 작업을 수행하는 가장 우아한(한 줄, 명확하게 이해되는) 방법은 무엇입니까?
답변1
원래 명령의 출력이 표시되는 이유는 지정된 파일뿐만 아니라 tee
출력 때문입니다. stdout
이를 중단하려면 이 출력을 명령 끝에 넣거나 >/dev/null
추가 를 추가하여 이 출력을 프로세스 교체 중 하나로 리디렉션할 수 있습니다 >
. 예를 들면 다음과 같습니다.
command | tee >(sed -rn 's/.*foo (bar).*/1/p') > >(awk '{print $3}')
또는 더 간단하게 다른 파이프를 사용하면 됩니다.
command | tee >(sed -rn 's/.*foo (bar).*/1/p') | awk '{print $3}'
결합된 두 프로세스 대체를 사용한 결과에 관해서는 paste
내가 알지 못하는 모호한 쉘 트릭이 있지 않는 한 명명된 파이프를 사용하지 않고 이를 수행할 수 있는 방법이 없습니다. 궁극적으로 이는 두 줄입니다(명확성을 높이기 위해 형식화됨).
mkfifo /tmp/myfifo
command |
tee >(sed -rn 's/.*foo (bar).*/1/p' >/tmp/myfifo) |
awk '{print $3}' |
paste /tmp/myfifo -
이것을 스크립트에 넣는 경우 임시 명명된 파이프를 생성하라는 제안을 사용하는 것도 고려해 볼 수 있습니다.여기.
답변2
당신이해야 할 일은 입니다 sed
.
command |
sed '/\([^ ][^ ]* *\)\{2\}/{h
s///;s/^ *//;s/ .*/p
g};s/.*foo \(bar\).*/\1/p;d'
하지만 다른 것에 관해서는, 당신은tee
에 대한문서 |pipe
:
cmd1 | {
{ tee /dev/fd/3 |
cmd2 >&2
} 3>&1 |
cmd3
} 2>&1 |paste
하지만 이미 사용하고 있으므로 sed
다음과 같이 사용할 수 있습니다.영리한 tee
필요한 경우에만 복사/리디렉션하세요.
cmd | {
sed -n 'p;s/.*foo \(bar\).*/\1/w /dev/fd/3' |
awk ...
} 2>&1
답변3
IMHO 더 우아하고 (명확하게 이해됨) "트릭"을 피합니다 tee
. @mikeserv
는 sed
. 명령을 사용한 명령 대체의 예 :awk
printf
$ printf "foo %s %s %s\n" {1..30}
foo 1 2 3
foo 4 5 6
foo 7 8 9
foo 10 11 12
foo 13 14 15
foo 16 17 18
foo 19 20 21
foo 22 23 24
foo 25 26 27
foo 28 29 30
요구사항(예):
붙여넣기 출력
sed -rn '/3/ s/[^ ]* ([^ ]*).*/\1/'
"3"이 있는 행만 선택하고 두 번째 필드를 가져옵니다.
첫 번째 숫자 1, 13, 22 및 28이 있는 행입니다.awk 'NR>2 {print $3}'
모든 행의 세 번째 필드 표시
요구 사항 1의 스트림은 배열로 캡처되고 bar
,
요구 사항 2의 스트림은 배열로 캡처됩니다 secondstream
.
모든 입력이 처리된 후 캡처된 스트림을 END 블록에 붙여넣습니다.
printf "foo %s %s %s\n" {1..30} |
awk '/3/ {bar[barcounter++]=$2}
NF>2 {secondstream[streamnr++]=$3}
END {for (i=0;i<streamnr;i++) print bar[i], secondstream[i];}
'
결과:
1 2
13 5
22 8
28 11
14
17
20
23
26
29