programing

셸 명령어 실행 및 출력 캡처

sourcejob 2022. 9. 20. 23:56
반응형

셸 명령어 실행 및 출력 캡처

셸 명령어를 실행하여 출력 결과를 문자열로 반환하는 함수를 작성하려고 합니다.이 함수는 에러 메시지든 성공 메시지든 상관없습니다.명령줄을 사용했을 때와 같은 결과를 얻고 싶을 뿐입니다.

그런 일을 할 수 있는 코드 예는 무엇일까요?

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

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(['ls', '-l'])
b'total 0\n-rw-r--r--  1 memyself  staff  0 Mar 14 11:04 files\n'

check_output는 인수만 1입력으로 받는 단일 프로그램을 실행합니다.인쇄된 그대로 결과를 반환한다.stdout.stdin ahead ahead ahead ahead the 로 넘어갑니다.run ★★★★★★★★★★★★★★★★★」Popen를 참조해 주세요.명령어를 하려면 , 「 」의 「 」를 참조해 .shell=True이 답변의 끝에 있습니다.

check_output함수는 공식적으로 유지 보수된 모든 버전의 Python에서 작동합니다.그러나 최신 버전에서는 보다 유연한 접근 방식을 사용할 수 있습니다.

Python(3.5) :run

만약 당신이 Python 3.5+사용하고 있고 하위 호환성이 필요하지 않다면, 새로운 기능은 대부분의 작업에 대해 공식 문서에서 권장한다.모듈에 대한 매우 일반적인 고급 API를 제공합니다.프로그램의 출력을 캡처하려면subprocess.PIPEstdout그럼 접속해 주세요.stdout반환되는 객체의 속성:

>>> 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 , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , , .bytesinput다음 중 하나:

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

할 수 있는 은 에러입니다.stderr=subprocess.PIPE: (예:)에)result.stderr ) 。stderr=subprocess.STDOUT: (예:)에)result.stdout」를 참조해 주세요.네가 원한다면run가 제로 했을 때 , 「0」을 패스할 수 .check=True ( )을 할 수 .returncode「」의 어트리뷰트result보안가 되지 않는 에는 보다 실행할 수도 있습니다.shell=True이 답변의 끝에 기술된 바와 같이

이후 버전의 Python은 위의 내용을 더욱 합리화합니다.Python 3.7+에서는 위의 한 줄의 철자가 다음과 같습니다.

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

「」를 사용합니다.run이 방법은 기존의 작업 방식에 비해 약간의 복잡성만 더합니다.다 할 수 되었습니다.run기능하고 있습니다.

버전의 Python (4) : Python (3-3.4) : about세정세check_output

Python을 호환성이 Python을 할 수 .check_output이치노Python 2.7 python python python python python python python python python python python python python python python python python.

subprocess.check_output(*popenargs, **kwargs)  

은 같은 합니다.Popen(아래 참조) 및 프로그램 출력을 포함하는 문자열을 반환합니다.이 답변의 첫머리에 보다 자세한 사용 예가 나와 있습니다..5 Python 3.5+의 check_output는 을 과 같습니다.runcheck=True ★★★★★★★★★★★★★★★★★」stdout=PIPE 「」만 한다.stdout여하하다

할 수 stderr=subprocess.STDOUT에러 메시지가 반환된 출력에 포함되도록 합니다.하지 않은 에는 보다 셸.shell=True이 답변의 끝에 기술된 바와 같이

stderr합니다.check_output를 참조해 주십시오.「 를 참조해 주세요.Popen★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★,

Python ( 2 . 6 ) 의 python python :Popen

한 호환성이 보다 check_output ★★★★★★★★★★★★★★★★★」run 직접 .Popen오브젝트: 서브프로세스의 저레벨 API를 캡슐화합니다.

Popen컨스트럭터는 인수를 지정하지 않고 단일 명령어를 받아들이거나 첫 번째 항목으로 명령어를 포함하는 목록과 그 뒤에 임의의 수의 인수를 포함하여 목록 내의 개별 항목으로 문자열을 적절한 형식의 목록으로 해석하는 데 있습니다. 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

Aaron Hall의 답변에 주목해 주십시오.이것은, 일부의 시스템에서는, 다음의 설정을 실시할 필요가 있는 경우가 있습니다.stdout,stderr , , , , 입니다.stdin to 의 allPIPE (오류)DEVNULL 구하다communicate을 사용하다

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

의 모든가 되지 않는 셸 할 수 .shell=True.

메모들

명령어를 합니다.1 . " " " :shell=True가 바뀌다

통상은, 「」, 「」에의 각 .run,check_output " " "Popen컨스트럭터는 단일 프로그램을 실행합니다.즉, 화려한 배쉬 스타일의 파이프가 없다는 뜻입니다.복잡한 셸 명령을 실행하려면shell=True아, 네, 네, 네, 네.예를 들어 다음과 같습니다.

>>> subprocess.check_output('cat books/* | wc', shell=True, text=True)
' 1299377 17005208 101299376\n'

그러나 이렇게 하면 보안에 대한 우려가 높아집니다.간단한 스크립팅 이외의 작업을 수행할 경우 각 프로세스를 개별적으로 호출하고 각 프로세스의 출력을 입력으로 다음 프로세스로 전달하는 것이 좋습니다.

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

또는

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

파이프를 직접 연결하려는 유혹이 강합니다. 저항하십시오.그렇지 않으면 교착 상태가 되거나 이와 같은 해킹 행위를 해야 할 수 있습니다.

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

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

(return_value, output)과 함께 태플을 반환합니다.

Python2 와의 양쪽 는, 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,

저도 같은 문제가 있었지만 매우 간단한 방법을 알아냈습니다.

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

도움이 되었으면 좋겠다

이 합니다: Python3는 Python3입니다.subprocess.getoutput()Python2 python python python2에 python python python python python python python python python python.

솔루션은 까다롭지만 매우 간단한 솔루션으로 많은 상황에서 작동합니다.

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

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

코멘트의 추가 메모:일회성 작업의 경우 tmp 파일을 삭제할 수 있습니다.이 작업을 여러 번 수행해야 하는 경우 tmp를 삭제할 필요가 없습니다.

os.remove('tmp')

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.popen('your command here').read()

주의: 이것은 python 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")

같은 문제의 풍미가 조금 달랐습니다.다음의 요건에 대해서입니다.

  1. STDOUT 버퍼에 누적된 STDOUT 메시지를 캡처하여 반환합니다(즉, 실시간으로).
    • @와 '생산량vartec을 하여 이 를 파이톤적으로
      의 키워드
  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)

마일리지가 변동될 수 있습니다.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]

자세한 내용을 알게 된 후 다른 핸들을 사용하는 커스텀 시스템에서 작업 중이기 때문에 모든 STD를 직접 제어해야 했기 때문에 이러한 파이프 인수가 필요하다고 생각합니다.

(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')

Python 3.7+에서는 use 및 passcapture_output=True:

import subprocess
result = subprocess.run(['echo', 'hello', 'world'], capture_output=True)
print(repr(result.stdout))

그러면 바이트가 반환됩니다.

b'hello world\n'

하려면 을 합니다.text=True:

result = subprocess.run(['echo', 'hello', 'world'], capture_output=True, text=True)
print(repr(result.stdout))

기본 인코딩을 사용하여 바이트를 읽습니다.

'hello world\n'

인코딩을 해야 할 를 합니다.encoding="your encoding"text=True:

result = subprocess.run(['echo', 'hello', 'world'], capture_output=True, encoding="utf8")
print(repr(result.stdout))

의 초기 분할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...'

여기에서는 프로세스 실행 중 또는 실행 중 출력 인쇄가 필요한 경우 해결 방법이 있습니다.


현재의 작업 디렉토리도 추가했습니다만, 몇 번인가 도움이 되었습니다.


솔루션이 누군가에게 도움이 되기를 바랍니다:).

import subprocess

def run_command(cmd_and_args, print_constantly=False, cwd=None):
"""Runs a system command.

:param cmd_and_args: the command to run with or without a Pipe (|).
:param print_constantly: If True then the output is logged in continuous until the command ended.
:param cwd: the current working directory (the directory from which you will like to execute the command)
:return: - a tuple containing the return code, the stdout and the stderr of the command
"""
output = []

process = subprocess.Popen(cmd_and_args, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd)

while True:
    next_line = process.stdout.readline()
    if next_line:
        output.append(str(next_line))
        if print_constantly:
            print(next_line)
    elif not process.poll():
        break

error = process.communicate()[1]

return process.returncode, '\n'.join(output), error

어떤 이유로 Python 2.7에서 동작하며 os만 Import하면 됩니다!

import os 

def bash(command):
    output = os.popen(command).read()
    return output

print_me = bash('ls -l')
print(print_me)

여러 파일에 대해 셸 명령을 실행해야 하는 경우 이 방법으로 해결했습니다.

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

편집: 방금 Max Persson의 J.F. 솔루션을 확인했습니다.세바스찬의 제안.그것을 도입했습니다.

@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에서 명령어를 실행하는 것과 동일하게 동작합니다.

그그 、 기상상향향향 향향향향 。
출력을 향상시키기 위해 반복기를 사용할 수 있습니다.보면 는 더 .

from subprocess import Popen, getstatusoutput, PIPE
def shell_command(cmd):
    result = Popen(cmd, shell=True, stdout=PIPE, stderr=PIPE)

    output = iter(result.stdout.readline, b'')
    error = iter(result.stderr.readline, b'')
    print("##### OutPut ###")
    for line in output:
        print(line.decode("utf-8"))
    print("###### Error ########")
    for line in error:
        print(error.decode("utf-8")) # Convert bytes to str

    status, terminal_output = run_command(cmd)
    print(terminal_output)

shell_command("ls") # this will display all the files & folders in directory

getstatus 출력을 사용하는 기타 메서드(이해하기 쉬움)

from subprocess import Popen, getstatusoutput, PIPE

status_Code, output = getstausoutput(command)
print(output) # this will give the terminal output

# status_code, output = getstatusoutput("ls") # this will print the all files & folder available in the directory

「 」를하고 있는 는,subprocesspython module, STDOUT, STDERR 반환 코드.완전한 명령어 발신자의 실장의 예를 참조할 수 있습니다. '하다'로 할 수 있습니다.try..except네가 원한다면.

다음 함수는 STDOUT, STDERR 및 Return 코드를 반환하여 다른 스크립트로 처리할 수 있도록 합니다.

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

검토 대상으로 simppl을 제안하고 싶습니다.이 모듈은 pypi를 통해 사용할 수 있습니다.pip install simpplpython3는 python3는 python3는 python3를 사용합니다.

simppl 를 사용하면 셸 명령어를 실행하여 화면에서 출력을 읽을 수 있습니다.

개발자들은 세 가지 유형의 사용 사례를 제안합니다.

  1. 가장 간단한 사용법은 다음과 같습니다.
    from simppl.simple_pipeline import SimplePipeline
    sp = SimplePipeline(start=0, end=100):
    sp.print_and_run('<YOUR_FIRST_OS_COMMAND>')
    sp.print_and_run('<YOUR_SECOND_OS_COMMAND>') ```

  1. 여러 명령을 동시에 실행하려면 다음을 사용합니다.
    commands = ['<YOUR_FIRST_OS_COMMAND>', '<YOUR_SECOND_OS_COMMAND>']
    max_number_of_processes = 4
    sp.run_parallel(commands, max_number_of_processes) ```

  1. 마지막으로 프로젝트에서 CLI 모듈을 사용하는 경우 파이프라인의 일부로 다른 command_line_tool을 직접 실행할 수 있습니다.다른 도구는 동일한 프로세스에서 실행되지만 로그에서 파이프라인의 다른 명령으로 나타납니다.이를 통해 다른 도구를 호출하는 도구를 보다 원활하게 디버깅하고 리팩터링할 수 있습니다.
    from example_module import example_tool
    sp.print_and_run_clt(example_tool.run, ['first_number', 'second_nmber'], 
                                 {'-key1': 'val1', '-key2': 'val2'},
                                 {'--flag'}) ```

의 STDOUT/STDERR를 .logging★★★★★★ 。


다음은 simppl의 동작을 나타내는 완전한 코드입니다.

import logging
from logging.config import dictConfig

logging_config = dict(
    version = 1,
    formatters = {
        'f': {'format':
              '%(asctime)s %(name)-12s %(levelname)-8s %(message)s'}
        },
    handlers = {
        'h': {'class': 'logging.StreamHandler',
              'formatter': 'f',
              'level': logging.DEBUG}
        },
    root = {
        'handlers': ['h'],
        'level': logging.DEBUG,
        },
)
dictConfig(logging_config)

from simppl.simple_pipeline import SimplePipeline
sp = SimplePipeline(0, 100)
sp.print_and_run('ls')

다음은 셸 모드에서 IPython을 사용하는 다양한 OS 버전과 Python 2 및 3 모두에서 작동하는 단순하고 유연한 솔루션입니다.

from IPython.terminal.embed import InteractiveShellEmbed
my_shell = InteractiveShellEmbed()
result = my_shell.getoutput("echo hello world")
print(result)

Out: ['hello world']

몇 가지 장점이 있습니다.

  1. IPython 설치만 필요하므로 사용 시 특정 Python 또는 OS 버전에 대해 걱정할 필요가 없습니다. 광범위한 지원을 제공하는 Jupyter가 포함되어 있습니다.
  2. 기본적으로는 단순한 문자열이 필요하므로 셸 모드 arg 또는 문자열 분할을 사용할 필요가 없으므로 IMO가 약간 깨끗해집니다.
  3. 또한 문자열 자체에서 변수 또는 전체 Python 명령을 쉽게 대체할 수 있습니다.

데모 방법:

var = "hello world "
result = my_shell.getoutput("echo {var*2}")
print(result)

Out: ['hello world hello world']

특별히 Jupyter가 이미 설치되어 있는 경우 추가 옵션을 제공하고자 합니다.

물론 .py 스크립트가 아닌 실제 Jupyter 노트북에 있는 경우 언제든지 다음 작업을 수행할 수 있습니다.

result = !echo hello world
print(result)

같은 일을 이루다.

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

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

예를 들어, 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 ""

언급URL : https://stackoverflow.com/questions/4760215/running-shell-command-and-capturing-the-output

반응형