하위 프로세스를 사용하여 파이프로 여러 프로세스를 연결하려면 어떻게합니까?

StackOverflow https://stackoverflow.com/questions/295459

  •  08-07-2019
  •  | 
  •  

문제

파이썬을 사용하여 다음 쉘 명령을 어떻게 실행합니까? subprocess 기준 치수?

echo "input data" | awk -f script.awk | sort > outfile.txt

입력 데이터는 문자열에서 나올 것이므로 실제로는 필요하지 않습니다. echo. 나는 이것을 멀리 가지고있다, 누구든지 내가 어떻게 파이프를 통과하는지 설명 할 수 있습니까? sort 도?

p_awk = subprocess.Popen(["awk","-f","script.awk"],
                          stdin=subprocess.PIPE,
                          stdout=file("outfile.txt", "w"))
p_awk.communicate( "input data" )

업데이트: 아래에 허용 된 답변은 실제로 질문에 대답하지는 않지만 S.Lott가 옳다고 생각하며 처음에는 그 문제를 해결하지 않아도되는 것이 좋습니다!

도움이 되었습니까?

해결책

당신은 다음과 같이 조금 더 행복 할 것입니다.

import subprocess

awk_sort = subprocess.Popen( "awk -f script.awk | sort > outfile.txt",
    stdin=subprocess.PIPE, shell=True )
awk_sort.communicate( b"input data\n" )

작업의 일부를 쉘에 위임하십시오. 두 프로세스를 파이프 라인과 연결하도록하십시오.

당신은 'script.awk'를 파이썬으로 재 작성하여 AWK와 파이프 라인을 제거 할 수 있습니다.

편집하다. AWK가 도움이되지 않는다고 제안하는 이유 중 일부는 도움이되지 않습니다.

의견을 통해 응답해야 할 이유가 너무 많습니다.

  1. AWK는 유의 한 가치가없는 단계를 추가하고 있습니다. Python이 처리하지 않는 AWK의 처리에는 독특한 것이 없습니다.

  2. 대규모 데이터 세트의 경우 awk에서 정렬까지 파이프 라인은 경과 처리 시간을 향상시킬 수 있습니다. 짧은 데이터 세트의 경우 큰 이점이 없습니다. 빠른 측정 awk >file ; sort file 그리고 awk | sort 동시성이 드러날 것입니다. 정렬을 사용하면 정렬이 한 번의 스루 필터가 아니기 때문에 거의 도움이되지 않습니다.

  3. "Python to awk to storm"대신 "Python to Sort"처리의 단순성은 여기에서 묻는 정확한 종류의 질문을 방지합니다.

  4. 파이썬 (Python)은 AWK보다 Wordier는 또한 AWK가 초보자에게 불투명하고 비전문가에게 혼란스러운 암시 적 규칙을 가지고있는 경우에도 명백합니다.

  5. AWK (쉘 스크립트 자체와 같은)는 또 다른 프로그래밍 언어를 추가합니다. 이 모든 것이 한 언어 (Python)로 수행 할 수 있다면 쉘을 제거하고 AWK 프로그래밍을 제거하면 두 개의 프로그래밍 언어가 제거되어 누군가가 작업의 가치 생산 부분에 집중할 수 있습니다.

결론 : Awk는 상당한 가치를 더할 수 없습니다. 이 경우 AWK는 순 비용입니다. 이 질문을해야 할 충분한 복잡성을 추가했습니다. awk를 제거하는 것은 순 이익이 될 것입니다.

사이드 바 파이프 라인 구축 이유 (a | b) 너무 힘들다.

껍질이 직면 할 때 a | b 다음을 수행해야합니다.

  1. 원래 껍질의 어린이 과정을 포크합니다. 이것은 결국 b가 될 것입니다. b.

  2. OS 파이프를 만듭니다. (파이썬 하위 프로세스가 아님) 그러나 호출하십시오 os.pipe() 공통 버퍼를 통해 연결된 두 개의 새 파일 설명자가 반환됩니다. 이 시점 에서이 과정에는 부모의 stdin, stdout, stderr와 "a 's stdout"및 "b's stdin"이 될 파일이 있습니다.

  3. 아이 포크. 어린이는 성별을 새로운 A의 stdout으로 교체합니다. exec a 프로세스.

  4. B Child는 Stdin을 새로운 B의 Stdin으로 대체합니다. exec b 프로세스.

  5. B 아이는 A가 완료되기를 기다립니다.

  6. 부모는 B가 완료되기를 기다리고 있습니다.

위의 것은 재귀 적으로 스폰 할 수 있다고 생각합니다. a | b | c, 그러나 당신은 긴 파이프 라인을 암시 적으로 괄호로 만들어서 마치 마치 마치 처리해야합니다. a | (b | c).

파이썬이 있기 때문에 os.pipe(), os.exec() 그리고 os.fork(), 그리고 당신은 교체 할 수 있습니다 sys.stdin 그리고 sys.stdout, 순수한 파이썬에서 위의 방법이 있습니다. 실제로, 당신은 os.pipe() 그리고 subprocess.Popen.

그러나 해당 작업을 쉘에 위임하는 것이 더 쉽습니다.

다른 팁

import subprocess

some_string = b'input_data'

sort_out = open('outfile.txt', 'wb', 0)
sort_in = subprocess.Popen('sort', stdin=subprocess.PIPE, stdout=sort_out).stdin
subprocess.Popen(['awk', '-f', 'script.awk'], stdout=sort_in, 
                 stdin=subprocess.PIPE).communicate(some_string)

쉘 파이프 라인을 모방하려면 :

from subprocess import check_call

check_call('echo "input data" | a | b > outfile.txt', shell=True)

쉘을 호출하지 않고 (참조 17.1.4.2. 쉘 파이프 라인 교체):

#!/usr/bin/env python
from subprocess import Popen, PIPE

a = Popen(["a"], stdin=PIPE, stdout=PIPE)
with a.stdin:
    with a.stdout, open("outfile.txt", "wb") as outfile:
        b = Popen(["b"], stdin=a.stdout, stdout=outfile)
    a.stdin.write(b"input data")
statuses = [a.wait(), b.wait()] # both a.stdin/stdout are closed already

plumbum 일부 구문 설탕을 제공합니다.

#!/usr/bin/env python
from plumbum.cmd import a, b # magic

(a << "input data" | b > "outfile.txt")()

아날로그 :

#!/bin/sh
echo "input data" | awk -f script.awk | sort > outfile.txt

이다:

#!/usr/bin/env python
from plumbum.cmd import awk, sort

(awk["-f", "script.awk"] << "input data" | sort > "outfile.txt")()

http://www.python.org/doc/2.5.2/lib/node535.html 이것을 꽤 잘 덮었습니다. 당신이 이해하지 못한 것의 일부가 있습니까?

귀하의 프로그램은 꽤 비슷하지만 두 번째는 Popen 파일에 stdout =가있을 것이고, 당신은 그것의 출력이 필요하지 않을 것입니다. .communicate().

@Cristian의 답변에서 영감을 얻었습니다. 나는 같은 문제를 만났지만 다른 명령으로 만났습니다. 그래서 나는 테스트 된 예제를 제시하고 있습니다. 도움이 될 수 있다고 생각합니다.

grep_proc = subprocess.Popen(["grep", "rabbitmq"],
                             stdin=subprocess.PIPE, 
                             stdout=subprocess.PIPE)
subprocess.Popen(["ps", "aux"], stdout=grep_proc.stdin)
out, err = grep_proc.communicate()

이것은 테스트되었습니다.

한 일

  • 게으른 선언 grep 파이프에서 stdin으로 실행. 이 명령은에서 실행됩니다 ps 파이프가 stdout으로 채워질 때 명령 실행 ps.
  • 기본 명령이라고합니다 ps Stdout과 함께 grep 명령.
  • Grep은 파이프에서 stdout을 얻기 위해 통신했습니다.

나는 이런 식으로 부드럽게 싸인 천연 파이프 개념이기 때문에 subprocess 인터페이스.

허용 된 대답은 문제를 회피하는 것입니다. 다음은 여러 프로세스의 출력을 사로하는 스 니펫입니다. 또한 (다소) 동등한 쉘 명령을 인쇄하여 실행하고 출력이 올바른지 확인할 수 있습니다.

#!/usr/bin/env python3

from subprocess import Popen, PIPE

# cmd1 : dd if=/dev/zero bs=1m count=100
# cmd2 : gzip
# cmd3 : wc -c
cmd1 = ['dd', 'if=/dev/zero', 'bs=1M', 'count=100']
cmd2 = ['tee']
cmd3 = ['wc', '-c']
print(f"Shell style : {' '.join(cmd1)} | {' '.join(cmd2)} | {' '.join(cmd3)}")

p1 = Popen(cmd1, stdout=PIPE, stderr=PIPE) # stderr=PIPE optional, dd is chatty
p2 = Popen(cmd2, stdin=p1.stdout, stdout=PIPE)
p3 = Popen(cmd3, stdin=p2.stdout, stdout=PIPE)

print("Output from last process : " + (p3.communicate()[0]).decode())

# thoretically p1 and p2 may still be running, this ensures we are collecting their return codes
p1.wait()
p2.wait()
print("p1 return: ", p1.returncode)
print("p2 return: ", p2.returncode)
print("p3 return: ", p3.returncode)

편집하다: pipes Windows에서 사용할 수 있지만 결정적으로는 실제로 보이지 않습니다. 일하다 창에. 아래의 의견을 참조하십시오.

Python Standard Library에는 이제 The가 포함되어 있습니다 pipes 이것을 처리하기위한 모듈 :

https://docs.python.org/2/library/pipes.html, https://docs.python.org/3.4/library/pipes.html

이 모듈이 얼마나 오래 있었는지 잘 모르겠지만,이 접근법은 subprocess.

이전 답변은 중요한 요점을 놓쳤다. 쉘 파이프 라인 교체 Geocar가 지적한대로 기본적으로 정확합니다. 그것은이다 거의 실행하기에 충분합니다 communicate 파이프의 마지막 요소에.

나머지 문제는 전달됩니다 입력 데이터 파이프 라인에. 다중 하위 프로세스를 사용하면 간단합니다 communicate(input_data) 마지막 요소에서는 작동하지 않습니다. 영원히 매달려 있습니다. AA 파이프 라인을 만들고 다음과 같은 수동으로 어린이를 만들어야합니다.

import os
import subprocess

input = """\
input data
more input
""" * 10

rd, wr = os.pipe()
if os.fork() != 0: # parent
    os.close(wr)
else:              # child
    os.close(rd)
    os.write(wr, input)
    os.close(wr)
    exit()

p_awk = subprocess.Popen(["awk", "{ print $2; }"],
                         stdin=rd,
                         stdout=subprocess.PIPE)
p_sort = subprocess.Popen(["sort"], 
                          stdin=p_awk.stdout,
                          stdout=subprocess.PIPE)
p_awk.stdout.close()
out, err = p_sort.communicate()
print (out.rstrip())

이제 어린이는 파이프를 통한 입력을 제공하고 부모는 Communice ()에게 예상대로 작동합니다. 이 접근법을 사용하면 "작업의 일부를 쉘에 위임"에 의지하지 않고 임의의 긴 파이프 라인을 만들 수 있습니다. 불행히도 하위 프로세스 문서 이것을 언급하지 않습니다.

파이프없이 동일한 효과를 달성하는 방법이 있습니다.

from tempfile import TemporaryFile
tf = TemporaryFile()
tf.write(input)
tf.seek(0, 0)

이제 사용하십시오 stdin=tf ~을 위한 p_awk. 당신이 선호하는 맛의 문제입니다.

상기는 신호 처리가 다르기 때문에 여전히 Bash 파이프 라인과 100% 동등하지 않습니다. 출력을 자르는 다른 파이프 요소를 추가하면 이것을 볼 수 있습니다. sort, 예를 들어 head -n 10. 위의 코드를 사용하여 sort "파손 파이프"오류 메시지를 stderr. 쉘에서 동일한 파이프 라인을 실행할 때이 메시지가 표시되지 않습니다. (그래도 유일한 차이점입니다. 결과는 stdout 는 똑같은). 그 이유는 그 파이썬의 것 같습니다 Popen 세트 SIG_IGN ~을 위한 SIGPIPE, 껍질은 그것을 떠난다 SIG_DFL, 그리고 sort이 두 경우에는 신호 처리가 다릅니다.

나를 위해 아래의 접근 방식은 가장 깨끗하고 읽기가 가장 쉽습니다.

from subprocess import Popen, PIPE

def string_to_2_procs_to_file(input_s, first_cmd, second_cmd, output_filename):
    with open(output_filename, 'wb') as out_f:
        p2 = Popen(second_cmd, stdin=PIPE, stdout=out_f)
        p1 = Popen(first_cmd, stdout=p2.stdin, stdin=PIPE)
        p1.communicate(input=bytes(input_s))
        p1.wait()
        p2.stdin.close()
        p2.wait()

그렇게 부를 수 있습니다.

string_to_2_procs_to_file('input data', ['awk', '-f', 'script.awk'], ['sort'], 'output.txt')
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top