쉘 명령 실행 및 출력 캡처


907

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

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

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

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'

답변:


1138

이 질문에 대한 답변은 사용중인 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 에서는 객체를 반환합니다. 아직 유니 코드대해 배우지 않으면 시간을내어 살펴볼 가치가 있습니다.


5
와 모두 check_output()communicate()당신과 과정이 완료 될 때까지 기다릴 필요가 poll()온다대로 출력을 받고 있습니다. 실제로 필요한 것에 달려 있습니다.
vartec

2
이것이 이후 버전의 Python에만 적용되는지 확실하지 않지만 변수 out<class 'bytes'>나에게 적합했습니다. 출력을 문자열로 얻으려면 다음과 같이 인쇄하기 전에 디코딩해야했습니다.out.decode("utf-8")
PolyMesh

1
@par 통과하면 효과가 shell=True없습니까? 그것은 나를 위해 작동합니다. shlex.split통과 할 때 필요하지 않습니다 shell=True. shlex.split쉘이 아닌 명령입니다. 나는 이것이 물을 흐릿하게하기 때문에 그 비트를 꺼낼 것이라고 생각합니다.
senderle

2
Python 3.5 이상에서는 universal_newlines=True시스템의 기본 인코딩에서 유니 코드 문자열을 전달하고 가져올 수있는 키워드 인수 가 허용됩니다. 3.7에서 이것은 더 현명한 것으로 개명되었다 text=True.
tripleee 2018 년

2
Python 3.6 이상에서는을 사용하는 대신 encoding매개 변수를 사용할 수 있습니다 . subprocess.runresult.stdout.decode('utf-8')subprocess.run(['ls', '-l'], stdout=subprocess.PIPE, encoding='utf-8')
Pierre

191

이것은 훨씬 쉽지만 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

31
subprocess.check_output없이 오래된 파이썬 버전 지금,하지만 매우 유용한 추천하지 않습니다
static_rtti

22
이것은 유닉스 전용입니다. 예를 들어 Windows에서는 실패합니다.
Zitrax

4
+1 고대 버전의 python 2.4에서 작업해야하는데 이것은 매우 도움이되었습니다
javadba

1
PIPE 친구는 전체 코드를 보여줍니다 : subprocess.PIPE
Kyle Bridenstine

@KyleBridenstine 당신은 답변을 편집 할 수 있습니다.
Boris

106

그런 것 :

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,

잠재적 교착 상태 waitcall기능 을 피하기 위해 출력을 얻으려면 일종의 활성 루프를 구현해야 합니다.
André Caron

@Silver Light : 프로세스가 아마도 사용자의 입력을 기다리고있을 것입니다. 파일을 반환 하자마자 PIPE값을 제공 stdin하고 닫으십시오 Popen.
André Caron

4
-1 : if retcode가 무한 루프 입니다 0. 확인해야합니다 if retcode is not None. 빈 문자열을 만들면 안됩니다 (빈 줄은 적어도 하나의 기호 '\ n'입니다) if line: yield line. p.stdout.close()마지막에 전화 하십시오.
jfs

2
나는 ls -l / dirname으로 코드를 시험
해봤는데

3
@fuenfundachtzig : 모든 출력을 읽을 .readlines()때까지 반환 되지 않으므로 메모리에 맞지 않는 큰 출력에서는 끊어집니다. 또한 서브 프로세스가 종료 된 후 버퍼링 된 데이터가 누락되지 않도록하려면 다음과 같은 아날로그가 있어야합니다.if retcode is not None: yield from p.stdout.readlines(); break
jfs

67

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)

6
return iter(p.stdout.readline, b'')while 루프 대신 사용할 수 있습니다
jfs

2
그것은 iter의 꽤 멋진 사용법입니다, 그것을 몰랐습니다! 코드를 업데이트했습니다.
Max Ekman 21:53에

stdout이 모든 출력을 유지한다고 확신합니다. 버퍼가있는 스트림 객체입니다. 나는 Popen이 완료 된 후 남아있는 모든 출력을 고갈시키는 매우 유사한 기술을 사용하며, 필자의 경우에는 실행 중에 poll () 및 readline을 사용하여 출력을 실시간으로 캡처합니다.
맥스 에크 만

오해의 소지가있는 의견을 삭제했습니다. 내가 확인할 수 p.stdout.readline()자식 프로세스가 이미 종료 한 경우에도 비어 있지 않은 이전에 버퍼링 된 출력을 반환 할 수 있습니다 ( p.poll()아니다 None).
jfs

이 코드는 작동하지 않습니다. 여기를 참조하십시오 stackoverflow.com/questions/24340877/…
thang

61

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

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

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

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

os.remove('tmp')

5
Hacky 그러나 매우 간단하고 어디서나 작동합니다 .. mktemp스레드 상황에서 작동하도록 결합 할 수 있습니다.
Prakash Rajagaopal

2
가장 빠른 방법 일지 모르지만 os.remove('tmp')"파일이없는" 방법으로 추가 하는 것이 좋습니다 .
XuMuK

@XuMuK 당신은 일회성 작업의 경우에 맞습니다. 반복적 인 작업이라면 삭제가 필요하지 않습니다.
Mehdi Saman Booy

1
동시성, 재진입 기능, 시스템을 시작하기 전과 같이 그대로 두지 않는 문제 (정리 없음)
2mia

1
@ 2mia 분명히 이유가 쉽습니다! 파일을 동시 읽기 및 쓰기를위한 일종의 공유 메모리로 사용하려는 경우 이는 좋은 선택이 아닙니다. 그러나 s.th. 명령의 출력 (예 : ls 또는 find 또는 ...)을 갖는 것과 같이 좋고 빠른 선택이 될 수 있습니다. 간단한 문제에 대한 빠른 솔루션이 필요한 경우 Btw가 가장 좋습니다. 파이프 라인이 필요한 경우 하위 프로세스가 더 효율적입니다.
Mehdi Saman Booy

44

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

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

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

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


이것이 OP 문제를 어떻게 해결합니까? 정교하게 작성하십시오.
RamenChef

4
명령의 출력을 문자열처럼 간단하게 반환합니다.
azhar22k

1
물론 print는 Python 2에 대한 진술입니다. 이것이 Python 3 답변이라는 것을 알 수 있습니다.

2
@Dev 인쇄는 유효한 파이썬 2입니다. subprocess.getoutput이 아닙니다.
user48956

2
대부분의 사용 사례에서 사람들이 원할 것입니다. 기억하기 쉽고 결과를 해독 할 필요가 없습니다. 감사합니다.
bwv549

18

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

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")

2
버전 2.6부터 사용되지 않음 – docs.python.org/2/library/os.html#os.popen
Filippo Vitale

1
@FilippoVitale 감사합니다. 더 이상 사용되지 않는다는 것을 몰랐습니다.
무하마드 하산

1
raspberrypi.stackexchange.com/questions/71547/… 에 따르면 os.popen()Python 2.6에서는 더 이상 사용되지 않지만 3.x에서는를 사용하여 구현되므로 Python 3.x에서는 더 이상 사용 되지 않습니다 subprocess.Popen().
JL

12

마일리지가 다를 수 있습니다 .Python 2.6.5의 Windows에서 Vartec 솔루션에 대한 @senderle의 스핀을 시도했지만 오류가 발생하여 다른 솔루션이 작동하지 않았습니다. 내 오류는 : WindowsError: [Error 6] The handle is invalid.

나는 예상 한 출력을 반환하기 위해 모든 핸들에 PIPE를 할당해야한다는 것을 알았습니다. 다음은 저에게 효과적이었습니다.

import subprocess

def run_command(cmd):
    """given shell command, returns communication tuple of stdout and stderr"""
    return subprocess.Popen(cmd, 
                            stdout=subprocess.PIPE, 
                            stderr=subprocess.PIPE, 
                            stdin=subprocess.PIPE).communicate()

다음과 같이 호출 [0]하십시오 (튜플의 첫 번째 요소를 얻습니다 stdout).

run_command('tracert 11.1.0.1')[0]

더 많은 것을 배우고 나면 다른 핸들을 사용하는 사용자 지정 시스템에서 작업하기 때문에 이러한 파이프 인수가 필요하다고 생각하므로 모든 표준을 직접 제어해야했습니다.

Windows에서 콘솔 팝업을 중지하려면 다음을 수행하십시오.

def run_command(cmd):
    """given shell command, returns communication tuple of stdout and stderr"""
    # instantiate a startupinfo obj:
    startupinfo = subprocess.STARTUPINFO()
    # set the use show window flag, might make conditional on being in Windows:
    startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
    # pass as the startupinfo keyword argument:
    return subprocess.Popen(cmd,
                            stdout=subprocess.PIPE, 
                            stderr=subprocess.PIPE, 
                            stdin=subprocess.PIPE, 
                            startupinfo=startupinfo).communicate()

run_command('tracert 11.1.0.1')

1
흥미 롭습니다-이것은 Windows 일이어야합니다. 사람들이 비슷한 오류를 겪을 경우를 대비하여 메모를 추가하겠습니다.
senderle

사용 DEVNULL대신subprocess.PIPE사용자가 작성하지 않은 경우 / 그렇지 않으면 당신은 자식 프로세스를 중지 될 수 있습니다 파이프에서 읽을.
jfs

10

다음 요구 사항과 동일한 문제의 맛이 약간 다릅니다.

  1. STDOUT 메시지가 STDOUT 버퍼에 누적 될 때 (즉, 실시간으로) 캡처하고 리턴합니다.
    • @vartec은 생성기를 사용하고 위의 'yield'
      키워드를 사용 하여이 문제를 파이썬으로 해결했습니다.
  2. 모든 STDOUT 행을 인쇄하십시오 ( STDOUT 버퍼를 완전히 읽기 전에 프로세스가 종료 된 경우에도 )
  3. 고주파로 프로세스를 폴링하는 CPU 사이클을 낭비하지 마십시오.
  4. 서브 프로세스의 리턴 코드를 확인하십시오.
  5. 0이 아닌 오류 리턴 코드가 발생하면 STDERR (STDOUT과 별도로)을 인쇄하십시오.

이전 답변을 결합하고 조정하여 다음을 수행했습니다.

import subprocess
from time import sleep

def run_command(command):
    p = subprocess.Popen(command,
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE,
                         shell=True)
    # Read stdout from subprocess until the buffer is empty !
    for line in iter(p.stdout.readline, b''):
        if line: # Don't print blank lines
            yield line
    # This ensures the process has completed, AND sets the 'returncode' attr
    while p.poll() is None:                                                                                                                                        
        sleep(.1) #Don't waste CPU-cycles
    # Empty STDERR buffer
    err = p.stderr.read()
    if p.returncode != 0:
       # The run_command() function is responsible for logging STDERR 
       print("Error: " + str(err))

이 코드는 이전 답변과 동일하게 실행됩니다.

for line in run_command(cmd):
    print(line)

1
절전 (.1)을 추가해도 CPU주기가 낭비되지 않는 방법에 대해 설명 하시겠습니까?
Moataz Elmasry

2
호출 p.poll()사이에 아무런 수면없이 계속 호출하면이 기능을 수백만 번 호출하여 CPU주기를 낭비하게됩니다. 대신, 우리는 OS에게 다음 1/10 초 동안 귀찮게 할 필요가 없다고 말함으로써 루프를 "스로틀 링"하여 다른 작업을 수행 할 수 있습니다. (p.poll ()도 잠 들어 잠자기 설명이 중복 될 수 있습니다).
Aelfinn

5

에 대한 초기 명령을 나누는 subprocess것은 까다 롭고 번거로울 수 있습니다.

shlex.split()자신을 돕기 위해 사용하십시오 .

샘플 명령

git log -n 5 --since "5 years ago" --until "2 year ago"

코드

from subprocess import check_output
from shlex import split

res = check_output(split('git log -n 5 --since "5 years ago" --until "2 year ago"'))
print(res)
>>> b'commit 7696ab087a163e084d6870bb4e5e4d4198bdc61a\nAuthor: Artur Barseghyan...'

shlex.split()코드가 없으면 다음과 같이 보일 것입니다

res = check_output([
    'git', 
    'log', 
    '-n', 
    '5', 
    '--since', 
    '5 years ago', 
    '--until', 
    '2 year ago'
])
print(res)
>>> b'commit 7696ab087a163e084d6870bb4e5e4d4198bdc61a\nAuthor: Artur Barseghyan...'

1
shlex.split()특히 쉘에서 정확하게 인용하는 방법을 모르는 경우 편리합니다. 그러나 ['git', 'log', '-n', '5', '--since', '5 years ago', '--until', '2 year ago']인용을 이해하면 이 문자열을 목록으로 수동으로 변환하는 것이 전혀 어렵지 않습니다.
tripleee

4

여러 파일에서 쉘 명령을 실행 해야하는 경우이 트릭을 수행했습니다.

import os
import subprocess

# Define a function for running commands and capturing stdout line by line
# (Modified from Vartec's solution because it wasn't printing all lines)
def runProcess(exe):    
    p = subprocess.Popen(exe, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    return iter(p.stdout.readline, b'')

# Get all filenames in working directory
for filename in os.listdir('./'):
    # This command will be run on each file
    cmd = 'nm ' + filename

    # Run the command and capture the output line by line.
    for line in runProcess(cmd.split()):
        # Eliminate leading and trailing whitespace
        line.strip()
        # Split the output 
        output = line.split()

        # Filter the output and print relevant lines
        if len(output) > 2:
            if ((output[2] == 'set_program_name')):
                print filename
                print line

편집 : JF Sebastian의 제안으로 Max Persson의 솔루션을 보았습니다. 앞서 가서 그것을 통합했습니다.


Popen문자열을 받아들이지 만 shell=True, 또는 인수 목록 이 필요 ['nm', filename]합니다.이 경우 문자열 대신 전달해야 합니다. 후자는 쉘이 여기서 가치를 제공하지 않고 복잡성을 추가하기 때문에 바람직하다. 문자열을 전달하지 않으면 shell=True분명히 Windows에서 작동하지만 다음 파이썬 버전에서는 변경 될 수 있습니다.
tripleee

2

@ senderle에 따르면, 나와 같은 python3.6을 사용하는 경우 :

def sh(cmd, input=""):
    rst = subprocess.run(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, input=input.encode("utf-8"))
    assert rst.returncode == 0, rst.stderr.decode("utf-8")
    return rst.stdout.decode("utf-8")
sh("ls -a")

bash에서 명령을 실행하는 것처럼 정확하게 작동합니다.


당신은 키워드 인수를 재발 명하고 check=True, universal_newlines=True있습니다. 즉, subprocess.run()이미 코드가 수행하는 모든 작업을 수행합니다.
tripleee

1

subprocess파이썬 모듈 을 사용하면 STDOUT, STDERR 및 명령의 리턴 코드를 별도로 처리 할 수 ​​있습니다. 완전한 명령 호출자 구현에 대한 예를 볼 수 있습니다. 물론 try..except원한다면 확장 할 수도 있습니다 .

아래 함수는 STDOUT, STDERR 및 리턴 코드를 리턴하므로 다른 스크립트에서 처리 할 수 ​​있습니다.

import subprocess

def command_caller(command=None)
    sp = subprocess.Popen(command, stderr=subprocess.PIPE, stdout=subprocess.PIPE, shell=False)
    out, err = sp.communicate()
    if sp.returncode:
        print(
            "Return code: %(ret_code)s Error message: %(err_msg)s"
            % {"ret_code": sp.returncode, "err_msg": err}
            )
    return sp.returncode, out, err

또 다른 불완전한 구현 subprocess.run() . 바퀴를 재발 명하지 마십시오.
tripleee 2018 년

0

예를 들어, execute ( 'ls -ahl')는 3/4 개의 가능한 수익과 OS 플랫폼을 차별화했습니다.

  1. 출력은 없지만 성공적으로 실행
  2. 빈 줄 출력, 성공적으로 실행
  3. 실행 실패
  4. 무언가를 출력하고 성공적으로 실행

아래 기능

def execute(cmd, output=True, DEBUG_MODE=False):
"""Executes a bash command.
(cmd, output=True)
output: whether print shell output to screen, only affects screen display, does not affect returned values
return: ...regardless of output=True/False...
        returns shell output as a list with each elment is a line of string (whitespace stripped both sides) from output
        could be 
        [], ie, len()=0 --> no output;    
        [''] --> output empty line;     
        None --> error occured, see below

        if error ocurs, returns None (ie, is None), print out the error message to screen
"""
if not DEBUG_MODE:
    print "Command: " + cmd

    # https://stackoverflow.com/a/40139101/2292993
    def _execute_cmd(cmd):
        if os.name == 'nt' or platform.system() == 'Windows':
            # set stdin, out, err all to PIPE to get results (other than None) after run the Popen() instance
            p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True)
        else:
            # Use bash; the default is sh
            p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True, executable="/bin/bash")

        # the Popen() instance starts running once instantiated (??)
        # additionally, communicate(), or poll() and wait process to terminate
        # communicate() accepts optional input as stdin to the pipe (requires setting stdin=subprocess.PIPE above), return out, err as tuple
        # if communicate(), the results are buffered in memory

        # Read stdout from subprocess until the buffer is empty !
        # if error occurs, the stdout is '', which means the below loop is essentially skipped
        # A prefix of 'b' or 'B' is ignored in Python 2; 
        # it indicates that the literal should become a bytes literal in Python 3 
        # (e.g. when code is automatically converted with 2to3).
        # return iter(p.stdout.readline, b'')
        for line in iter(p.stdout.readline, b''):
            # # Windows has \r\n, Unix has \n, Old mac has \r
            # if line not in ['','\n','\r','\r\n']: # Don't print blank lines
                yield line
        while p.poll() is None:                                                                                                                                        
            sleep(.1) #Don't waste CPU-cycles
        # Empty STDERR buffer
        err = p.stderr.read()
        if p.returncode != 0:
            # responsible for logging STDERR 
            print("Error: " + str(err))
            yield None

    out = []
    for line in _execute_cmd(cmd):
        # error did not occur earlier
        if line is not None:
            # trailing comma to avoid a newline (by print itself) being printed
            if output: print line,
            out.append(line.strip())
        else:
            # error occured earlier
            out = None
    return out
else:
    print "Simulation! The command is " + cmd
    print ""

0

출력을 텍스트 파일로 리디렉션 한 다음 다시 읽을 수 있습니다.

import subprocess
import os
import tempfile

def execute_to_file(command):
    """
    This function execute the command
    and pass its output to a tempfile then read it back
    It is usefull for process that deploy child process
    """
    temp_file = tempfile.NamedTemporaryFile(delete=False)
    temp_file.close()
    path = temp_file.name
    command = command + " > " + path
    proc = subprocess.run(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
    if proc.stderr:
        # if command failed return
        os.unlink(path)
        return
    with open(path, 'r') as f:
        data = f.read()
    os.unlink(path)
    return data

if __name__ == "__main__":
    path = "Somepath"
    command = 'ecls.exe /files ' + path
    print(execute(command))

물론 가능 하지만 왜 그렇게 하시겠습니까? 그리고 왜 전달하는 대신 쉘을 사용 stdout=temp_file하겠습니까?
tripleee

사실, 일반적으로 당신은 옳지 만 내 예에서는 ecls.exe다른 명령 줄 도구를 배포 하는 것처럼 보이므로 간단한 방법이 때로는 작동하지 않았습니다.
MR

0

curl을 사용 하여이 작업을 수행하는 작은 bash 스크립트를 작성했습니다.

https://gist.github.com/harish2704/bfb8abece94893c53ce344548ead8ba5

#!/usr/bin/env bash

# Usage: gdrive_dl.sh <url>

urlBase='https://drive.google.com'
fCookie=tmpcookies

curl="curl -L -b $fCookie -c $fCookie"
confirm(){
    $curl "$1" | grep jfk-button-action | sed -e 's/.*jfk-button-action" href="\(\S*\)".*/\1/' -e 's/\&amp;/\&/g'
}

$curl -O -J "${urlBase}$(confirm $1)"
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.