복붙노트

[PYTHON] 셸 명령 실행 및 출력 캡쳐

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'

해결법

  1. ==============================

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

    이 질문에 대한 답변은 사용중인 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에 입력을 작성해야하는 경우 run 또는 Popen 섹션으로 건너 뛰십시오. 복잡한 셸 명령을 실행하려면이 대답 끝의 shell = True에 대한 참고 사항을 참조하십시오.

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

    파이썬 3.5 이상을 사용 중이며 역 호환성이 필요없는 경우 새로운 실행 기능을 사용하는 것이 좋습니다. 서브 프로세스 모듈을위한 매우 일반적인 고급 API를 제공합니다. 프로그램의 출력을 캡처하려면 subprocess.PIPE 플래그를 stdout 키워드 인수에 전달하십시오. 그런 다음 반환 된 CompletedProcess 객체의 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'
    

    반환 값은 바이트 객체이므로 적절한 문자열이 필요하면 디코딩해야합니다. 호출 된 프로세스가 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'
    

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

    >>> 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를 전달하여보다 복잡한 쉘 명령을 실행할 수도 있습니다.

    이것은 일을하는 옛 방식에 비해 약간의 복잡성을 더합니다. 하지만 이제는 그만한 가치가 있다고 생각합니다. 이제는 단독으로 달리기 기능으로 할 수있는 거의 모든 것을 할 수 있습니다.

    이전 버전의 Python을 사용하거나 겸손한 하위 호환성이 필요한 경우 위에 간략히 설명한대로 check_output 함수를 사용할 수 있습니다. 그것은 Python 2.7부터 사용 가능합니다.

    subprocess.check_output(*popenargs, **kwargs)  
    

    소요되는 인수는 Popen (아래 참조)과 동일한 인수를 사용하고 프로그램의 출력을 포함하는 문자열을 반환합니다. 이 답변의 시작 부분에는보다 자세한 사용 예가 나와 있습니다.

    stderr = subprocess.STDOUT을 전달하여 오류 메시지가 반환 된 출력에 포함되도록 할 수 있지만 check_output에 stderr = subprocess.PIPE를 전달하지 마십시오. 교착 상태가 발생할 수 있습니다. 보안 문제가 아니라면, 아래의 주석에서 설명하는 것처럼 shell = True를 전달하여보다 복잡한 쉘 명령을 실행할 수도 있습니다.

    stderr에서 파이프해야하거나 입력을 프로세스로 전달해야하는 경우 check_output은 해당 작업을 수행하지 않습니다. 이 경우 아래의 Popen 예제를 참조하십시오.

    역방향 호환성이 필요하거나 check_output이 제공하는 것보다 더 정교한 기능이 필요한 경우 하위 프로세스 용 저수준 API를 캡슐화하는 Popen 객체로 직접 작업해야합니다.

    Popen 생성자는 인수가없는 단일 명령 또는 첫 번째 항목으로 명령을 포함하는 목록을 하나씩 받아들이며, 그 다음에 목록의 개별 항목으로 구성된 인수를 지정합니다. shlex.split은 문자열을 적절하게 형식화 된 목록으로 파싱하는 데 도움을 줄 수 있습니다. Popen 객체는 또한 프로세스 IO 관리 및 저수준 구성에 대해 여러 가지 다른 인수를 허용합니다.

    입력 및 캡처 출력을 보내려면 거의 항상 통신이 선호되는 방법입니다. 마찬가지로 :

    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를 설정하면 통신을 통해 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 all을 PIPE (또는 DEVNULL)로 설정하여 통신이 작동 할 필요가 있음을 나타내는 Aaron Hall의 대답을 참고하십시오.

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

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

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

    일반적으로 run, check_output 또는 Popen 생성자에 대한 각 호출은 단일 프로그램을 실행합니다. 그건 멋진 bash 스타일의 파이프가 아니라는 뜻입니다. 복잡한 셸 명령을 실행하려면 shell = True를 전달하면됩니다.이 함수는 세 가지 기능 모두를 지원합니다.

    그러나 이렇게하면 보안 문제가 야기됩니다. 가벼운 스크립팅 이상의 작업을 수행하는 경우 각 프로세스를 개별적으로 호출하는 것이 더 좋을 수 있으며 각 프로세스를 입력으로 전달하고 다음 프로세스로 전달할 수 있습니다.

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

    또는

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

    파이프를 직접 연결하려는 유혹이 강하다. 그것을 저항하라. 그렇지 않으면 교착 상태가 발생하거나 이와 같은 해킹이 발생해야합니다.

    2. 유니 코드 고려 사항

    check_output은 파이썬 2에서 문자열을 반환하지만 파이썬 3에서는 바이트 객체를 반환합니다. 아직없는 경우 유니 코드에 대해 배우려면 잠시 시간을내어 볼 가치가 있습니다.

  2. ==============================

    2.이것은 더 쉽지만 Unix (Cygwin 포함)에서만 작동합니다.

    이것은 더 쉽지만 Unix (Cygwin 포함)에서만 작동합니다.

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

    (return_value, output)을 가진 튜플을 리턴한다.

    이 기능은 python2.7에서만 작동합니다 : python3에서는 사용할 수 없습니다. 두 가지 모두에서 작동하는 솔루션의 경우 하위 프로세스 모듈을 대신 사용하십시오.

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

    3.그와 같은 것 :

    그와 같은 것 :

    def runProcess(exe):    
        p = subprocess.Popen(exe, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
        while(True):
          retcode = p.poll() #returns None while subprocess is running
          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,
    
  4. ==============================

    4.Vartec의 답은 모든 행을 읽지는 않습니다. 그래서 제가 한 버전을 만들었습니다 :

    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)
    
  5. ==============================

    5.이것은 여러 상황에서 작동하는 까다 롭지 만 아주 간단한 솔루션입니다.

    이것은 여러 상황에서 작동하는 까다 롭지 만 아주 간단한 솔루션입니다.

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

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

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

    os.remove('tmp')
    
  6. ==============================

    6.파이썬 3.5에서 :

    파이썬 3.5에서 :

    import subprocess
    
    output = subprocess.run("ls -l", shell=True, stdout=subprocess.PIPE, 
                            universal_newlines=True)
    print(output.stdout)
    
  7. ==============================

    7.현대 파이썬 솔루션 (> = 3.1) :

    현대 파이썬 솔루션 (> = 3.1) :

     res = subprocess.check_output(lcmd, stderr=subprocess.STDOUT)
    
  8. ==============================

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

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

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

    9.나는 똑같은 문제가 있었다. 그러나 이것을하는 아주 간단한 방법을 알아 냈습니다. 이것을 따라라.

    나는 똑같은 문제가 있었다. 그러나 이것을하는 아주 간단한 방법을 알아 냈습니다. 이것을 따라라.

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

    희망이 도움이됩니다.

    참고 :이 솔루션은 python3에서만 사용할 수 있습니다. subprocess.getoutput ()은 python2에서 작동하지 않습니다.

  10. ==============================

    10.귀하의 마일리지가 달라질 수 있습니다. Python 2.6.5에서 Windows의 Vartec 솔루션에 @ senderle의 스핀을 시도했지만 오류가 발생했으며 다른 해결책은 없습니다. 내 오류 : WindowsError : [오류 6] 핸들이 잘못되었습니다.

    귀하의 마일리지가 달라질 수 있습니다. Python 2.6.5에서 Windows의 Vartec 솔루션에 @ senderle의 스핀을 시도했지만 오류가 발생했으며 다른 해결책은 없습니다. 내 오류 : WindowsError : [오류 6] 핸들이 잘못되었습니다.

    나는 내가 예상 한 결과를 얻기 위해 모든 핸들에 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')
    
  11. ==============================

    11.다음 요구 사항과 동일한 문제에 약간 다른 맛이났습니다.

    다음 요구 사항과 동일한 문제에 약간 다른 맛이났습니다.

    나는 다음과 같은 것을 내놓기 위해 이전의 답을 결합하고 조정했다.

    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)
    
  12. ==============================

    12.여러 파일에서 쉘 명령을 실행해야하는 경우, 이것은 나에게 트릭입니다.

    여러 파일에서 쉘 명령을 실행해야하는 경우, 이것은 나에게 트릭입니다.

    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
    

    편집 : J.F. Sebastian의 제안으로 Max Pansson의 솔루션을 보았습니다. 앞서 가서 통합했습니다.

  13. ==============================

    13.예 : execute ( 'ls -ahl') 차별화 된 3/4 가능한 회수 및 OS 플랫폼 :

    예 : execute ( 'ls -ahl') 차별화 된 3/4 가능한 회수 및 OS 플랫폼 :

    아래 기능

    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 ""
    
  14. from https://stackoverflow.com/questions/4760215/running-shell-command-and-capturing-the-output by cc-by-sa and MIT license