여러 명령에 stdout을 보내려면 어떻게합니까?


186

입력에 따라 필터링하거나 입력 한 다음 출력으로 전달하는 stdout명령이 있습니다. 보통 생각합니다 . 그러나 일부 명령은 stdin수행하고 수행하는 모든 작업을 수행하고 아무것도 출력하지 않습니다.

나는 OS X의 대부분 알고 있어요 그래서 바로 마음에 와서 두가 pbcopypbpaste- 시스템 클립 보드에 액세스 수단있는합니다.

어쨌든 stdout을 가져 와서 출력을 뱉어 stdout파일과 둘 다로 이동 하려면 tee명령을 사용할 수 있다는 것을 알고 있습니다 . 그리고에 대해 조금 알고 xargs있지만 그것이 내가 찾고있는 것이라고 생각하지 않습니다.

stdout두 개 이상의 명령 사이를 이동하기 위해 어떻게 분할 할 수 있는지 알고 싶습니다 . 예를 들면 다음과 같습니다.

cat file.txt | stdout-split -c1 pbcopy -c2 grep -i errors

거기보다 더 좋은 예는 아마도,하지만 난 정말 내가 그것을 릴레이하지 않는 명령에 표준 출력을 보낼 수있는 방법을 아는에 관심과 유지하면서 stdout"음소거"되는 것을 - 나는 방법에 대해 물어 아니에요 cat파일 및 grep그것의 일부를 클립 보드에 복사하십시오-특정 명령은 그렇게 중요하지 않습니다.

또한-나는 이것을 파일로 보내는 방법을 묻지 않고 있는데 stdout-이것은 "중복"질문 일 수 있지만 (미안하지만) stdout과 파일 사이에서 나누는 방법에 대해 묻는 비슷한 질문 만 찾았습니다. -그리고 그 질문에 대한 대답은 것 같았 tee습니다.

마지막으로, "pbcopy를 파이프 체인에서 마지막으로 만드는 것이 어떻습니까?" 내 응답은 1) 그것을 사용하고 콘솔에서 여전히 출력을 보려면 어떻게해야합니까? 2) stdout입력을 처리 한 후에 출력되지 않는 두 개의 명령을 사용하려면 어떻게해야 합니까?

아, 그리고 한 가지 더-나는 사용할 수 tee있고 명명 된 파이프 ( mkfifo)를 알 수 있지만 사전 설정없이 간결하게 인라인으로 수행 할 수있는 방법을 원했습니다. :)


답변:


239

tee이를 대체하고 사용 하고 처리 할 수 있습니다 .

cat file.txt | tee >(pbcopy) | grep errors

이 모든 출력 보내드립니다 cat file.txt에를 pbcopy, 그리고 당신 만의 결과 얻을 것이다 grep콘솔에 있습니다.

tee부품 에 여러 프로세스를 넣을 수 있습니다 .

cat file.txt | tee >(pbcopy) >(do_stuff) >(do_more_stuff) | grep errors

21
에 대한 우려는 pbcopy없지만 일반적으로 언급 할 가치가 있습니다 . 프로세스 대체 출력은 원래 입력 후 다음 파이프 세그먼트 에서도 볼 수 있습니다. 예 : seq 3 | tee >(cat -n) | cat -e( cat -n입력 라인에 번호를 cat -e매기고 , 줄 바꿈을 표시 합니다. 원래 입력 (첫 번째)과 (그다음)의 출력 모두에 적용됨을 $알 수 cat -e있습니다 cat -n). 의 출력 여러 프로세스 치환은 비 결정적 순서로 도착합니다.
mklement0

49
에서 >(유일한 작품 bash. 예를 들어 사용하려고하면 sh작동하지 않습니다. 이 통지를하는 것이 중요합니다.
AAlvz

10
@AAlvz : 좋은 점 : 프로세스 대체는 POSIX 기능 이 아닙니다 . dash, 역할을하는 sh우분투, 그것을 지원, 심지어 배쉬 자체로 호출 기능 비활성화하지 않는 sh경우 또는 set -o posix효과입니다. 그러나 프로세스 대체를 지원하는 것은 Bash뿐만 아니라 다른 것도 확실하지 않은 프로세스 대체 kshzsh지원합니다.
mklement0

2
사실이 아닌 @ mklement0. zsh (Ubuntu 14.04)에서 라인 인쇄는 다음과 같습니다.
Aktau

2
@Aktau는 :에 설명 된대로 실제로, 내 샘플 명령은 작동 bash하고 ksh- zsh분명히 파이프 라인 (틀림없이, 그건 통해 출력 프로세스 치환의 출력을 보내지 않는 것이 바람직 가 다음 파이프 라인 세그먼트로 전송 무엇을 오염시키지 않기 때문에, -하지만 여전히)를 인쇄 합니다. 에서 모든 출력 순서는 예측할 수 없으며 방식으로 드물게 또는 대형으로 표면 수 - 언급 조개, 그러나, 일반적으로 프로세스 치환에서 정기적으로 표준 출력 출력 및 출력이 혼합 된 하나의 파이프 라인을 가지고 좋은 생각이 아니다 출력 데이터 세트.
mklement0

124

에 여러 파일 이름을 지정할 tee수 있으며 표준 출력을 하나의 명령으로 파이프 할 수 있습니다. 출력을 여러 명령으로 디스패치하려면 여러 파이프를 작성하고 각각의 파이프를 하나의 출력으로 지정해야합니다 tee. 이를 수행하는 몇 가지 방법이 있습니다.

공정 대체

쉘이 ksh93, bash 또는 zsh 인 경우 프로세스 대체를 사용할 수 있습니다. 파일 이름이 필요한 명령에 파이프를 전달하는 방법입니다. 쉘은 파이프를 작성 /dev/fd/3하고 명령 과 같은 파일 이름을 전달합니다 . 숫자는 파이프가 연결된 파일 설명자 입니다. 일부 유닉스 변형은 지원하지 않습니다 /dev/fd. 이 경우 명명 된 파이프가 대신 사용됩니다 (아래 참조).

tee >(command1) >(command2) | command3

파일 기술자

POSIX 셸에서 여러 파일 설명자를 명시 적으로 사용할 수 있습니다 . /dev/fd출력 중 하나를 제외한 모든 출력을 tee이름으로 지정해야 하므로 이를 지원하는 유닉스 변형이 필요합니다 .

{ { { tee /dev/fd/3 /dev/fd/4 | command1 >&9;
    } 3>&1 | command2 >&9;
  } 4>&1 | command3 >&9;
} 9>&1

명명 된 파이프

가장 기본적이고 이식 가능한 방법은 명명 된 파이프 를 사용하는 것 입니다. 단점은 쓰기 가능한 디렉토리를 찾고 파이프를 생성 한 후 정리해야한다는 것입니다.

tmp_dir=$(mktemp -d)
mkfifo "$tmp_dir/f1" "$tmp_dir/f2"
command1 <"$tmp_dir/f1" & pid1=$!
command2 <"$tmp_dir/f2" & pid2=$!
tee "$tmp_dir/f1" "$tmp_dir/f2" | command3
rm -rf "$tmp_dir"
wait $pid1 $pid2

10
bash 또는 특정 ksh에 의존하고 싶지 않은 사람들을 위해 두 가지 대체 버전을 제공해 주셔서 대단히 감사합니다.
trr

tee "$tmp_dir/f1" "$tmp_dir/f2" | command3파이프의 command3 | tee "$tmp_dir/f1" "$tmp_dir/f2"표준 출력을 원할 때 반드시해야 합니까? 나는 당신의 버전을 테스트 하고 무기한으로 입력을 기다리고 있지만 주문을 전환하면 예상 결과가 나왔습니다. command3teedashtee
Adrian Günter

1
@ AdrianGünter 호 세가지 예는 표준 입력 데이터를 판독하고 각각 보내 command, command2command3.
Gilles

@Gilles, 나는 의도를 잘못 해석하고 스 니펫을 잘못 사용하려고했습니다. 설명 주셔서 감사합니다!
Adrian Günter

사용 된 쉘에 대한 제어 권한은 없지만 bash를 명시 적으로 사용할 수 있다면 할 수 있습니다 <command> | bash -c 'tee >(command1) >(command2) | command3'. 그것은 내 경우에 도움이되었습니다.
gc5

16

프로세스 대체로 재생하십시오.

mycommand_exec |tee >(grep ook > ook.txt) >(grep eek > eek.txt)

grepmycommand_exec프로세스 별 입력과 동일한 출력을 갖는 두 개의 이진입니다 .


16

사용하는 경우 기능의 zsh장점을 활용할 수 있습니다 MULTIOS. 즉 tee명령을 완전히 제거하십시오 .

uname >file1 >file2

단지의 출력을 기록 할 uname두 개의 서로 다른 파일을 : file1file2, 무슨의 동등uname | tee file1 >file2

마찬가지로 표준 입력의 리디렉션

wc -l <file1 <file2

의 동일합니다 cat file1 file2 | wc -l(이 다르다는 점에 유의하시기 바랍니다 wc -l file1 file2개별적으로 각 파일의 줄 나중에 카운트 번호).

물론 MULTIOS프로세스 대체를 사용하여 출력을 파일이 아닌 다른 프로세스로 리디렉션 하는 데 사용할 수도 있습니다 . 예 :

echo abc > >(grep -o a) > >(tr b x) > >(sed 's/c/y/')

3
알아 둘만 한. MULTIOS은 기본적으로 켜져 있는 옵션 입니다 (및를 사용하여 끌 수 있음 unsetopt MULTIOS).
mklement0

6

명령에 의해 생성되는 상당히 작은 출력의 경우 출력을 임시 파일로 리디렉션하고 해당 임시 파일을 루프의 명령으로 보낼 수 있습니다. 실행 된 명령의 순서가 중요 할 때 유용 할 수 있습니다.

예를 들어 다음 스크립트가이를 수행 할 수 있습니다.

#!/bin/sh

temp=$( mktemp )
cat /dev/stdin > "$temp"

for arg
do
    eval "$arg" < "$temp"
done
rm "$temp"

테스트와 우분투 16.04에서 실행 /bin/sh으로 dash쉘 :

$ cat /etc/passwd | ./multiple_pipes.sh  'wc -l'  'grep "root"'                                                          
48
root:x:0:0:root:/root:/bin/bash

5

명령 STDOUT을 변수로 캡처하고 원하는 만큼 여러 번 재사용하십시오.

commandoutput="$(command-to-run)"
echo "$commandoutput" | grep -i errors
echo "$commandoutput" | pbcopy

캡처해야 할 경우 명령 끝에서 STDERR다음 2>&1과 같이 사용하십시오.

commandoutput="$(command-to-run 2>&1)"

3
변수는 어디에 저장됩니까? 큰 파일이나 그와 비슷한 것을 다루는 경우 많은 메모리가 필요하지 않습니까? 변수의 크기가 제한되어 있습니까?
cwd

1
$ commandoutput이 크면 파이프를 사용하고 대체하는 것이 더 좋습니다.
Nikhil Mulley

4
분명히이 솔루션은 출력 크기가 메모리에 쉽게 들어갈 수 있다는 것을 알고있을 때만 가능하며 다음 명령을 실행하기 전에 전체 출력을 버퍼링해도됩니다. 파이프는 임의의 길이의 데이터를 허용하고 생성시 수신기로 실시간 스트리밍하여이 두 가지 문제를 해결합니다.
trr

2
작은 출력이 있고 출력이 이진이 아닌 텍스트가된다는 것을 알면 좋은 솔루션입니다. (쉘 변수는 종종 이진 안전하지 않습니다)
Rucent88

1
이진 데이터로 작동하도록 할 수 없습니다. 에코가 null 바이트 또는 다른 비 문자 데이터를 해석하려고하는 것으로 생각됩니다.
Rolf


0

다음을 포함한 모든 쉘과 호환되는 빠르고 더러운 부분 솔루션이 busybox있습니다.

더 좁은 문제는 stdout콘솔 하나에 콘솔을 인쇄하고 임시 파일이나 명명 된 파이프없이 다른 콘솔에이를 필터링하는 것입니다.

  • 동일한 호스트에서 다른 세션을 시작하십시오. TTY 이름을 찾으려면을 입력하십시오 tty. 가정합시다 /dev/pty/2.
  • 첫 번째 세션에서 다음을 실행하십시오. the_program | tee /dev/pty/2 | grep ImportantLog:

하나의 완전한 로그와 필터링 된 로그를 얻습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.