[python] 쉘 명령 실행 및 출력 캡처

쉘 명령을 실행하고 출력 을 문자열로 반환하는 함수를 작성하고 싶습니다 . 오류 또는 성공 메시지입니다. 명령 줄에서 얻은 것과 동일한 결과를 얻고 싶습니다.

그런 일을하는 코드 예제는 무엇입니까?

예를 들면 다음과 같습니다.

def run_command(cmd):
    # ??????

print run_command('mysqladmin create test -uroot -pmysqladmin12')
# Should output something like:
# mysqladmin: CREATE DATABASE failed; error: 'Can't create database 'test'; database exists'



답변

이 질문에 대한 답변은 사용중인 Python 버전에 따라 다릅니다. 가장 간단한 방법은 다음 subprocess.check_output함수 를 사용하는 것입니다.

>>> subprocess.check_output(['ls', '-l'])
b'total 0\n-rw-r--r--  1 memyself  staff  0 Mar 14 11:04 files\n'

check_output인수로만 입력하는 단일 프로그램을 실행합니다. 1 로 인쇄 된 그대로 결과를 반환합니다 stdout. 에 입력을 작성해야하는 경우 또는 섹션으로 stdin건너 뜁니다 . 복잡한 쉘 명령을 실행하려면 다음을 참고하십시오.runPopenshell=True 이 답변의 끝에 .

check_output함수는 여전히 널리 사용되는 거의 모든 버전의 Python에서 작동합니다 (2.7+). 2 그러나 최신 버전에서는 더 이상 권장되는 방법이 아닙니다.

최신 버전의 Python (3.5 이상) : run

Python 3.5 이상을 사용 하고 이전 버전과의 호환성이 필요하지 않은 경우 새로운 run기능 이 권장됩니다. subprocess모듈에 대한 매우 일반적인 고급 API를 제공합니다 . 프로그램의 출력을 캡처하려면 subprocess.PIPE플래그를 stdout키워드 인수에 전달하십시오. 그런 다음 stdout반환 된 CompletedProcess객체 의 속성에 액세스하십시오 .

>>> import subprocess
>>> result = subprocess.run(['ls', '-l'], stdout=subprocess.PIPE)
>>> result.stdout
b'total 0\n-rw-r--r--  1 memyself  staff  0 Mar 14 11:04 files\n'

반환 값은 bytes객체이므로 적절한 문자열을 원하면 필요 decode합니다. 호출 된 프로세스가 UTF-8로 인코딩 된 문자열을 리턴한다고 가정하십시오.

>>> result.stdout.decode('utf-8')
'total 0\n-rw-r--r--  1 memyself  staff  0 Mar 14 11:04 files\n'

이것은 모두 하나의 라이너로 압축 될 수 있습니다 :

>>> subprocess.run(['ls', '-l'], stdout=subprocess.PIPE).stdout.decode('utf-8')
'total 0\n-rw-r--r--  1 memyself  staff  0 Mar 14 11:04 files\n'

입력을 프로세스 stdin에 전달 bytes하려면 input키워드 인수에 객체를 전달하십시오.

>>> cmd = ['awk', 'length($0) > 5']
>>> input = 'foo\nfoofoo\n'.encode('utf-8')
>>> result = subprocess.run(cmd, stdout=subprocess.PIPE, input=input)
>>> result.stdout.decode('utf-8')
'foofoo\n'

stderr=subprocess.PIPE(캡처 대상 result.stderr) 또는 stderr=subprocess.STDOUT( result.stdout일반 출력과 함께 캡처 ) 을 전달하여 오류를 캡처 할 수 있습니다 . 보안이 중요하지 않은 경우 전달하여보다 복잡한 쉘 명령을 실행할 수도 있습니다.shell=True 아래 참고에 설명 된대로 하여 있습니다.

이것은 기존의 방식과 비교할 때 약간의 복잡성을 추가합니다. 하지만 그만한 가치가 있다고 생각합니다. 이제는run 기능만으로도 .

이전 버전의 Python (2.7-3.4) : check_output

이전 버전의 Python을 사용 중이거나 이전 버전과의 호환성이 필요한 경우 check_output위에서 간략히 설명한대로 함수를 사용할 수 있습니다 . 파이썬 2.7부터 사용 가능합니다.

subprocess.check_output(*popenargs, **kwargs)  

Popen(아래 참조) 와 동일한 인수 를 사용하여 프로그램의 출력을 포함하는 문자열을 반환합니다. 이 답변의 시작 부분에보다 자세한 사용 예가 있습니다. 파이썬 3.5보다에서 check_output실행하는 것과 동일하다 run으로 check=True하고 stdout=PIPE, 바로 반환stdout 속성.

당신은 통과 할 수 stderr=subprocess.STDOUT반환 된 출력에 포함되는 오류 메시지를 확인하기 위해 -하지만 파이썬은 전달의 일부 버전 stderr=subprocess.PIPEcheck_output캔 원인 교착 상태 . 보안이 중요하지 않은 경우 전달하여보다 복잡한 쉘 명령을 실행할 수도 있습니다.shell=True 아래 참고에 설명 된대로 하여 있습니다.

stderr프로세스 에서 파이프로 연결 하거나 입력을 전달 해야하는 경우 check_output작업에 달려 있지 않습니다. 참조Popen이 경우 아래 예를 .

복잡한 애플리케이션 및 레거시 버전의 Python (2.6 이하) : Popen

이전 버전과의 호환성이 필요하거나 제공하는 것보다 정교한 기능이 필요한 경우 하위 프로세스에 대한 하위 수준 API를 캡슐화하는 개체를 check_output직접 사용해야합니다 Popen.

Popen생성자 하나 받아 하나의 명령 인수없이 또는 목록 인자의 번호리스트에 별도 항목으로서 각각 다음의 첫 번째 항목으로 명령을 포함한다. shlex.split문자열을 적절한 형식의 목록으로 구문 분석하는 데 도움이 될 수 있습니다. Popen객체는 또한 다양한 인수를 허용합니다 프로세스 IO 관리 및 저수준 구성에 대한 를 합니다.

입력 및 캡처 출력을 전송하는 communicate것은 거의 항상 선호되는 방법입니다. 에서처럼 :

output = subprocess.Popen(["mycmd", "myarg"],
                          stdout=subprocess.PIPE).communicate()[0]

또는

>>> import subprocess
>>> p = subprocess.Popen(['ls', '-a'], stdout=subprocess.PIPE,
...                                    stderr=subprocess.PIPE)
>>> out, err = p.communicate()
>>> print out
.
..
foo

를 설정하면 stdin=PIPE, communicate또한이 과정을 통해 데이터를 전달 할 수 있습니다 stdin:

>>> cmd = ['awk', 'length($0) > 5']
>>> p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
...                           stderr=subprocess.PIPE,
...                           stdin=subprocess.PIPE)
>>> out, err = p.communicate('foo\nfoofoo\n')
>>> print out
foofoo

참고 아론 홀의 대답 일부 시스템에서 것을 나타냅니다, 당신은 설정해야 할 수도 있습니다 stdout, stderr그리고 stdin모두가 할 PIPE(또는 DEVNULL) 얻을 communicate전혀 작업에.

드문 경우이지만 복잡한 실시간 출력 캡처가 필요할 수 있습니다. Vartec 의 답변은 앞으로 나아갈 길을 제시하지만 communicate신중하게 사용하지 않으면 교착 상태에 빠지기 쉬운 방법 이 아닙니다.

위의 모든 기능과 마찬가지로 보안이 중요하지 않은 경우을 전달하여보다 복잡한 셸 명령을 실행할 수 있습니다 shell=True.

노트

1. 쉘 명령 실행 : shell=True인수

일반적으로 호출 할 때마다 run, check_output또는 Popen생성자는 실행 한 프로그램 . 그것은 멋진 배쉬 스타일 파이프가 없다는 것을 의미합니다. 복잡한 쉘 명령을 실행하려면 shell=True세 가지 기능 모두를 지원하는을 전달할 수 있습니다 .

그러나 이렇게하면 보안 문제가 발생 합니다. 간단한 스크립팅 이상의 작업을 수행하는 경우 각 프로세스를 개별적으로 호출하고 각 출력을 다음 입력을 통해 입력으로 전달하는 것이 좋습니다.

run(cmd, [stdout=etc...], input=other_output)

또는

Popen(cmd, [stdout=etc...]).communicate(other_output)

파이프를 직접 연결하려는 유혹이 강합니다. 그것을 저항하십시오. 그렇지 않으면, 당신은 가능성이 교착 상태를 참조하거나 같은 해키 일해야 할 것이다 .

2. 유니 코드 고려 사항

check_output파이썬 2에서는 문자열을 반환하지만 bytes파이썬 3 에서는 객체를 반환합니다. 아직 유니 코드대해 배우지 않으면 시간을내어 살펴볼 가치가 있습니다.


답변

이것은 훨씬 쉽지만 Unix (Cygwin 포함) 및 Python2.7에서만 작동합니다.

import commands
print commands.getstatusoutput('wc -l file')

(return_value, output)으로 튜플을 반환합니다.

Python2와 Python3에서 모두 작동하는 솔루션의 경우 subprocess대신 모듈을 사용하십시오.

from subprocess import Popen, PIPE
output = Popen(["date"],stdout=PIPE)
response = output.communicate()
print response


답변

그런 것 :

def runProcess(exe):
    p = subprocess.Popen(exe, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    while(True):
        # returns None while subprocess is running
        retcode = p.poll()
        line = p.stdout.readline()
        yield line
        if retcode is not None:
            break

stderr을 stdout으로 리디렉션하고 있는데 정확히 원하는 것이 아닐 수도 있지만 오류 메시지도 원합니다.

이 함수는 올 때마다 한 줄씩 출력합니다 (보통 서브 프로세스가 출력을 전체적으로 가져 오기를 기다려야합니다).

귀하의 경우 사용법은 다음과 같습니다.

for line in runProcess('mysqladmin create test -uroot -pmysqladmin12'.split()):
    print line,


답변

Vartec의 답변은 모든 줄을 읽지 못하므로 다음과 같은 버전을 만들었습니다.

def run_command(command):
    p = subprocess.Popen(command,
                         stdout=subprocess.PIPE,
                         stderr=subprocess.STDOUT)
    return iter(p.stdout.readline, b'')

사용법은 허용되는 답변과 동일합니다.

command = 'mysqladmin create test -uroot -pmysqladmin12'.split()
for line in run_command(command):
    print(line)


답변

이것은 많은 상황에서 작동 하는 까다 롭지매우 간단한 솔루션입니다.

import os
os.system('sample_cmd > tmp')
print open('tmp', 'r').read()

명령의 출력으로 임시 파일 (여기서는 tmp)이 작성되며 원하는 출력을 읽을 수 있습니다.

주석에서 추가 참고 사항 : 일회성 작업의 경우 tmp 파일을 제거 할 수 있습니다. 이 작업을 여러 번 수행해야하는 경우 tmp를 삭제할 필요가 없습니다.

os.remove('tmp')


답변

나는 같은 문제가 있었지만 이것을하는 매우 간단한 방법을 알아 냈습니다.

import subprocess
output = subprocess.getoutput("ls -l")
print(output)

그것이 도움이되기를 바랍니다.

참고 :이 솔루션은 Python2 subprocess.getoutput()에서 작동하지 않으므로 Python3 전용입니다.


답변

다음 명령을 사용하여 쉘 명령을 실행할 수 있습니다. 우분투에서 사용했습니다.

import os
os.popen('your command here').read()

참고 : 이것은 파이썬 2.6부터 더 이상 사용되지 않습니다. 이제를 사용해야합니다 subprocess.Popen. 아래는 예입니다

import subprocess

p = subprocess.Popen("Your command", shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()[0]
print p.split("\n")