쉘에서 여러 파일로 파이프


29

디스크에 저장하고 싶지 않은 대량의 데이터를 생성하는 응용 프로그램이 있습니다. 응용 프로그램은 주로 사용하지 않으려는 데이터를 출력하지만 별도의 파일로 분리 해야하는 유용한 정보를 제공합니다. 예를 들어 다음과 같은 출력이 주어집니다.

JUNK
JUNK
JUNK
JUNK
A 1
JUNK
B 5
C 1
JUNK

다음과 같이 응용 프로그램을 세 번 실행할 수 있습니다.

./app | grep A > A.out
./app | grep B > B.out
./app | grep C > C.out

이것은 내가 원하는 것을 얻을 것이지만 너무 오래 걸릴 것입니다. 또한 모든 출력을 단일 파일로 덤프하고 구문 분석하고 싶지 않습니다.

위의 세 가지 작업을 결합하여 응용 프로그램을 한 번만 실행하고 세 개의 별도 출력 파일을 얻는 방법이 있습니까?

답변:


78

가 있다면

./app | tee >(grep A > A.out) >(grep B > B.out) >(grep C > C.out) > /dev/null

( 여기에서 )

( 공정 대체에 대해 )


4
./app | tee >(grep A > A.out) >(grep B > B.out) | grep C > C.out
놀랍게도

7
이 답변은 질문의 원래 제목 "여러 프로세스에 파이프"를 고려할 때 현재 유일하게 정확한 답변입니다.
acelent

3
+1. 이는 특정 필터링 명령이라는 사실에 의존하지 않기 때문에 가장 일반적으로 적용되는 답변 grep입니다.
ruakh

1
나는 이것이 제기 된 질문에 대한 최선의 답변이며 동의해야한다는 데 동의합니다. 병렬 은 게시 된 다른 솔루션이지만 위의 예를 약간의 시간 비교를 한 것이 더 효율적입니다. op가 다중 파일 압축 또는 다중 mp3 변환과 같이 CPU를 많이 사용하는 작업과 관련이 있다면 병렬 솔루션이 더 효과적이라는 것이 의심의 여지가 없습니다 .
AsymLabs

32

당신이 사용할 수있는 awk

./app | awk '/A/{ print > "A.out"}; /B/{ print > "B.out"}; /C/{ print > "C.out"}'

6
질문의 제목은 여러 프로세스 에 대한 파이프입니다 .이 답변은 "파일링"(정규식으로 배포)에 대한 여러 파일 입니다. 이 답변이 수락되었으므로 질문 제목을 적절히 변경해야합니다.
acelent

@PauloMadeira 당신이 맞아요. 더 나은 타이틀이 무엇이라고 생각하십니까?
sj755

나는 매우 작은 편집을 제안했다. "쉘에 여러 파일로 파이프하기", 그것은 계류 중이다. 의견이 수락되면 의견을 제거 할 것으로 예상되었습니다.
acelent

@PauloMadeira-제목을 변경했습니다. 수정 된 내용이 보이지 않지만, 정답 인 경우 제목의 프로세스 사용이 올바르지 않습니다.
slm

17

쉘의 패턴 일치 기능을 사용할 수도 있습니다 .

./app | while read line; do 
     [[ "$line" =~ A ]] && echo $line >> A.out; 
     [[ "$line" =~ B ]] && echo $line >> B.out; 
     [[ "$line" =~ C ]] && echo $line >> C.out; 
 done

또는:

./app | while read line; do for foo in A B C; do 
     [[ "$line" =~ "$foo" ]] && echo $line >> "$foo".out; 
  done; done

백 슬래시와 라인으로 처리 할 수있는보다 안전한 방법 -:

./app | while IFS= read -r line; do for foo in A B C; do 
     [[ "$line" =~ "$foo" ]] && printf -- "$line\n" >> "$foo".out; 
  done; done

@StephaneChazelas가 의견에서 지적했듯이 이것은 매우 효율적이지 않습니다. 가장 좋은 해결책은 아마도 @ AurélienOoms ' 입니다.


입력에 백 슬래시, 공백 또는 와일드 카드 문자 또는으로 시작하는 행이 포함되어 있지 않다고 가정합니다 -n. -e... 한 줄에 여러 번의 시스템 호출 ( read(2)문자 당 하나씩 , 파일이 열려 있음, 쓰기 중)을 의미하므로 매우 비효율적입니다 각 줄마다 닫힙니다 ...). 일반적으로 while read쉘에서 텍스트를 처리하기 위해 루프를 사용하는 것은 좋지 않습니다.
Stéphane Chazelas

@ StephaneChazelas 내 답변을 편집했습니다. 백 슬래시 -n등으로 작동해야합니다 . 그래도 두 버전이 모두 공백으로 작동한다고 말할 수 있다면 잘못 되었습니까?
terdon

아니요, 첫 번째 인수 printf는 형식입니다. 거기에 변수를 인용하지 않은 채로 둘 이유가 없습니다.
Stéphane Chazelas

입력에 널이 있으면 bash (및 비슷한 방식으로 cstring을 사용하는 다른 쉘)에서도 중단됩니다.
Chris Down

9

코어가 여러 개이고 프로세스를 병렬화하려면 다음을 수행하십시오.

parallel -j 3 -- './app | grep A > A.out' './app | grep B > B.out' './app | grep C > C.out'

병렬 코어에서 3 개의 프로세스가 생성됩니다. 콘솔 또는 마스터 파일로 출력을 원할 경우 출력을 혼합하는 대신 출력을 일정한 순서로 유지하는 이점이 있습니다.

Ole Tange의 병렬 gnu 유틸리티 는 parallel 또는 moreutils 라는 이름으로 대부분의 저장소 에서 얻을 수 있습니다 . 출처는 Savannah.gnu.org 에서 구할 수 있습니다 . 또한 소개 교육용 비디오가 있습니다 .

추가

최신 버전의 병렬 (배포 저장소의 버전 일 필요는 없음)을 사용하여보다 우아한 구성을 사용할 수 있습니다.

./app | parallel -j3 -k --pipe 'grep {1} >> {1}.log' ::: 'A' 'B' 'C'

별도의 코어 또는 스레드에서 하나의 ./app 및 3 개의 병렬 grep 프로세스를 실행 한 결과를 얻습니다 (병렬 자체에 의해 결정된대로 -j3도 선택적인 것으로 간주하지만이 예제에서는 설명 목적으로 제공됨).

최신 버전의 병렬은 다음을 수행하여 얻을 수 있습니다.

wget http://ftpmirror.gnu.org/parallel/parallel-20131022.tar.bz2

그런 다음 일반적인 압축 풀기, cd to parallel- {date}, ./configure && make, sudo make install. 병렬, 맨 페이지 병렬 및 맨 페이지 parallel_tutorial을 설치합니다.


7

Perl에 하나 있습니다 :

./app | perl -ne 'BEGIN {open(FDA, ">A.out") and 
                         open(FDB, ">B.out") and 
                         open(FDC, ">C.out") or die("Cannot open files: $!\n")} 
                  print FDA $_ if /A/; print FDB $_ if /B/; print FDC $_ if /C/'

1
sed -ne/A/w\ A.out -e/B/w\ B.out -e/C/p <in >C.out

... <in읽을 수있는 경우 3 개의 아웃 파일이 모두 잘 리기 전에 잘립니다.

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