Python에서 호출할 때 이 bash 명령이 실행되지 않는 이유는 무엇입니까?

Python에서 호출할 때 이 bash 명령이 실행되지 않는 이유는 무엇입니까?

주문하다

$ find ~/foo/ -type f -iname "*.txt" -print0 | parallel -0 cat

사용GNU 병렬.txt아래의 모든 파일을 인쇄하십시오 ~/foo/.

이 bash 명령을 호출하려는 Python 스크립트가 있습니다.

import subprocess, sys

def runBashCommand(my_command):
    process = subprocess.Popen(my_command.split(), stdout=subprocess.PIPE)
    output  = process.communicate()[0]
    return None

def makeCommand(my_path):
    return "find {} -type f -iname \"*.txt\" -print0 | parallel -0 cat".format(my_path)

발행 된

>>> makeCommand('~/foo/')

반품

'find ~/foo/ -type f -iname "*.txt" -print0 | parallel -0 cat'

그러나 발행

>>> runBashCommand(makeCommand('~/foo/'))

오류 발생

find: paths must precede expression: |
Usage: find [-H] [-L] [-P] [-Olevel] [-D help|tree|search|stat|rates|opt|exec] [path...] [expression]

내 스크립트에 무슨 문제가 있나요?

답변1

bash실제로 명령을 실행하지 않습니다 . 당신이 하고 있는 일은 실행 파일을 직접 실행하고 인수를 전달하는 것입니다.

다음 스크립트를 시도해보고 무슨 일이 일어나는지 확인하세요.

import subprocess
p = subprocess.Popen(["echo", "a", "b", "|", "rev"], stdout=subprocess.PIPE)
print p.communicate()

출력은 다음과 같습니다:

('a b | rev\n', None)

리디렉션이 발생하지 않으며 "|"가 그대로 전달됩니다. 즉, 마치 자신이 입력한 것과 같습니다 find ... \| parallel .... 따라서 오류가 발생했습니다.

문제를 해결하는 방법에는 두 가지가 있습니다.

  • 가장 쉬운 방법은 shell=True에 전달하는 것입니다 subprocess.Popen. 이렇게 하면 필요한 모든 항목을 포함하여 셸을 통해 실행됩니다. 이렇게 하려면 배열 대신 문자열도 전달해야 합니다.

    import subprocess
    p = subprocess.Popen("echo a b | rev", stdout=subprocess.PIPE, shell=True)
    print p.communicate()
    
    # Result: ('b a\n', None)
    

    이렇게 하면,문자열의 매개변수 대체에는 매우 주의하세요..

  • 강력한 접근 방식: Python을 사용하여 두 프로세스를 열고 함께 연결합니다.

    import subprocess
    # First command
    p1 = subprocess.Popen(["echo", "a", "b"], stdout=subprocess.PIPE)
    # Second command's input linked to the first one's output
    p2 = subprocess.Popen(["rev"], stdin=p1.stdout, stdout=subprocess.PIPE)
    # Read from p2 to get the output
    print p2.communicate()
    
    # Result: ('b a\n', None)
    

    이는 더 강력하고 추가 쉘을 생성하지 않지만 반면에 더 많은 타이핑을 필요로 합니다. 이렇게 하면,알아채다아니요쉘 교체 발생. 귀하의 경우에는 필요하지 않은 것 같지만 을 사용하려면 ~Python(예: )을 통해 os.getenv("HOME")가져와야 합니다.

답변2

명령 문자열에는 및 split()등 셸에서 처리해야 하는 문자가 포함되어 있으므로 사용할 수 없습니다 . 사용 버전:~|

process = subprocess.Popen(my_command, stdout=subprocess.PIPE, shell=True)

관련 정보