콘텐츠를 독립적으로 유지하면서 프로그램 간에 여러 파일의 콘텐츠를 전송합니다.

콘텐츠를 독립적으로 유지하면서 프로그램 간에 여러 파일의 콘텐츠를 전송합니다.

많은 파일을 읽고 그 출력을 후속 프로그램으로 파이프하는 동시에 별도의 데이터 파이프라인으로 유지하고 싶습니다.

program1 *.txt | program2 | program3 folder

위의 구문이 단일 데이터 스트림에 대해 무엇을 수행할 수 있는지 알고 있지만 작업 전체에서 파일을 별도로 유지하는 것을 고려하고 있습니다. 위의 내용은 다음과 같이 번역됩니다.

  1. 프로그램 1은 텍스트 파일을 읽고 이를 프로그램 2로 파이프합니다.
  2. 프로그램 2는 데이터를 단독으로 처리하고 이를 프로그램 3으로 파이프합니다.
  3. program3은 원본 파일과 동일한 이름을 가진 폴더의 파일에 데이터를 씁니다.

이런 종류의 작업은 현재 Gulp와 같은 빌드 도구의 영역이지만 쉘이 이를 완전히 대체할 수 있는지 확인하려고 합니다. 프로그램은 하나만 처리하도록 작성되었기 때문에 stdin이는 실현 가능해 보이지 않습니다.

여러 파일을 읽고 쓰는 것은 프로그램 자체 내에서 처리하므로 문제가 되지 않습니다.

다음 사항을 조사했지만 올바른 해결책이 아닌 것 같습니다.

  • tee명령
  • 파일 설명자
  • 바꾸다

한 가지 가능한 접근 방식은 각 개별 파일에 대한 프로세스를 만들고 어딘가에 파일 이름 목록을 유지하는 것이지만 저는 좀 더 우아한 접근 방식을 원합니다.

답변1

다른 파일과 마찬가지로 파이프는 텍스트 스트림(보다 정확하게는 바이트 스트림)입니다. 유닉스의 기본 빌딩 블록은 단순한 경향이 있습니다. 프로세스 간의 상호 작용은 주로 비정형 데이터를 기반으로 합니다. 운영 체제는 파일 이름으로 레이블이 지정된 여러 스트림이 있는 통신 채널을 제공하지 않습니다. 프로그램이 이 작업을 수행해야 하는 경우 스트림당 파이프 하나씩 자체 파이프를 배열해야 하는 것이 가장 자연스러운 구현입니다.

program2및 가 각 스트림에 독립적으로 적용되는 경우 program3해당 복사본이 각 파일에 대해 실행됩니다. 순차적으로 실행하려면 쉘 루프를 사용하십시오. 파이프와 마찬가지로 루프는 프로그램을 서로 연결하는 셸 기능 중 하나입니다. 출력을 어디에 넣을지 알려주기 위해 program3일반적인 인터페이스는 program3표준 출력에 쓰고 출력을 파일로 지정하기 위해 셸의 리디렉션 구조를 사용하는 것입니다. 쉘은 파일 이름을 작성하기 위한 몇 가지 기본 문자열 조작 구성을 제공합니다. 이는 단지 연결일 뿐입니다.

for x in *.txt; do
  program1 "$x" | program2 | program3 >"folder/$x"
done

프로그램이 IO 집약적이지만 CPU 집약적이며 여러 개의 CPU가 있는 경우 병렬로 실행하는 것이 좋습니다. 충분히 새로운 GNU 도구를 사용하면 사용할 수 있습니다.xargs프로그램을 병렬로 실행합니다. 시스템의 CPU 수를 매개변수로 전달합니다 -P. 실행해야 하는 명령이 xargs파이프이므로 쉘을 호출하도록 만들어야 합니다.

find -maxdepth 1 -name '*.txt' -print0 |
xargs -0 -n 1 -P 4 sh -c 'program1 "$1" | program2 | program3 >"$0/$1"' "folder"

당신은 그것을 사용할 수 있습니다GNU 병렬xargs 대신 시스템의 CPU 수를 자동으로 결정합니다.

parallel sh -c 'program1 "$1" | program2 | program3 >"$0/$1"' "folder" ::: *.txt

단일 인스턴스가 필요 program2하고 program3여러 파일을 처리하는 경우 여러 파이프를 입력으로 수신하도록 사용자 정의 인터페이스를 사용하여 이러한 프로그램을 설계해야 합니다. 이를 수행하는 표준 방법은 없습니다. 한 가지 방법은 입력을 제공하는 프로그램을 호출하도록 하는 것입니다. 이는 출력을 처리하기 위해 어떤 프로그램을 호출할지 알려주는 것과 xargs비슷한 방식으로 작동합니다 .parallel

답변2

말을하는거야

program1 file1.txt   | program2 | program3 > folder/file1.txt
program1 file2.txt   | program2 | program3 > folder/file2.txt
program1 file42.txt  | program2 | program3 > folder/file42.txt
program1 green.txt   | program2 | program3 > folder/green.txt
program1 indigo.txt  | program2 | program3 > folder/indigo.txt
program1 leopard.txt | program2 | program3 > folder/leopard.txt
program1 lion.txt    | program2 | program3 > folder/lion.txt
   ⋮        ⋮            ⋮          ⋮                 ⋮ 

?

당신은 이것을 할 수 있습니다

for f in file1.txt file2.txt file42.txt green.txt indigo.txt leopard.txt lion.txt ...
do
    program1 "$f" | program2 | program3 > folder/"$f"
done

현재 디렉터리의 모든 텍스트 파일에 대해 이 작업을 수행하려면 와일드카드("globs"라고도 함)를 사용하면 됩니다.

for f in *.txt
do
    program1 "$f" | program2 | program3 > folder/"$f"
done

관련 정보