셸 명령 실행 및 출력 캡처
셸 명령을 실행하고 출력 을 문자열로 반환하는 함수를 작성하고 싶습니다 . 명령 줄에서 얻은 것과 동일한 결과를 얻고 싶습니다.
그런 일을하는 코드 예제는 무엇일까요?
예를 들면 :
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
건너 뜁니다 . 복잡한 쉘 명령을 실행하려면 이 답변 끝에 있는 참고를 참조하십시오 .run
Popen
shell=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
(capture to result.stderr
) 또는 stderr=subprocess.STDOUT
(capture to result.stdout
along with regular output) 을 전달하여 오류를 캡처 할 수 있습니다 . 보안이 중요하지 않은 경우 shell=True
아래 참고에 설명 된대로 전달 하여 더 복잡한 셸 명령을 실행할 수도 있습니다.
이것은 일을하는 기존 방식에 비해 약간의 복잡성을 추가합니다. 하지만 그만한 가치가 있다고 생각합니다. 이제 run
함수만으로 필요한 거의 모든 것을 할 수 있습니다 .
이전 버전의 Python (2.7-3.4) : check_output
이전 버전의 Python을 사용 중이거나 적절한 하위 호환성이 필요한 경우 check_output
위에서 간략하게 설명한대로 함수를 사용할 수 있습니다 . Python 2.7부터 사용할 수 있습니다.
subprocess.check_output(*popenargs, **kwargs)
Popen
(아래 참조) 와 동일한 인수를 취하고 프로그램의 출력을 포함하는 문자열을 반환합니다. 이 답변의 시작 부분에는 더 자세한 사용 예가 있습니다. 파이썬 3.5보다에서 check_output
실행하는 것과 동일하다 run
으로 check=True
하고 stdout=PIPE
, 바로 복귀 stdout
속성.
당신은 통과 할 수 stderr=subprocess.STDOUT
반환 된 출력에 포함되는 오류 메시지를 확인하기 위해 -하지만 파이썬은 전달의 일부 버전 stderr=subprocess.PIPE
에 check_output
캔 원인 교착 상태 . 보안이 중요하지 않은 경우 shell=True
아래 참고에 설명 된대로 전달 하여 더 복잡한 셸 명령을 실행할 수도 있습니다.
stderr
프로세스 에서 파이프 또는 입력을 전달 해야하는 경우 check_output
작업을 수행 할 수 없습니다. Popen
이 경우 아래 예를 참조하십시오 .
복잡한 애플리케이션 및 이전 버전의 Python (2.6 이하) : Popen
이전 버전과의 긴밀한 호환성이 필요하거나 check_output
제공 하는 것보다 더 정교한 기능이 필요한 경우 Popen
하위 프로세스에 대한 하위 수준 API를 캡슐화하는 개체를 직접 사용해야합니다 .
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
Aaron Hall의 대답에 유의하십시오 . 이는 일부 시스템 stdout
에서 stderr
, 및 stdin
모두를 PIPE
(또는 DEVNULL
)로 설정해야 작업을 수행 할 수 있음을 나타냅니다 communicate
.
드문 경우지만 복잡한 실시간 출력 캡처가 필요할 수 있습니다. Vartec 의 답변은 앞으로 나아갈 길을 제시하지만 communicate
신중하게 사용하지 않으면 다른 방법 이 교착 상태에 빠지기 쉽습니다.
위의 모든 함수와 마찬가지로 보안이 문제가되지 않는 경우를 전달하여 더 복잡한 셸 명령을 실행할 수 있습니다 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에서는 문자열을 반환하지만 bytes
파이썬 3 에서는 객체를 반환합니다. 유니 코드 에 대해 배우지 않았다면 잠시 시간을내어 배울 가치가 있습니다.
이 방법이 더 쉽지만 Unix (Cygwin 포함) 및 Python2.7에서만 작동합니다.
import commands
print commands.getstatusoutput('wc -l file')
(return_value, 출력)이있는 튜플을 반환합니다.
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()
참고 : 이것은 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")
귀하의 마일리지가 다를 수 있습니다. 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')
다음 요구 사항으로 동일한 문제에 대해 약간 다른 맛이 있습니다.
- STDOUT 버퍼에 누적되는 STDOUT 메시지를 캡처하고 반환합니다 (즉, 실시간).
- @vartec은 위의 생성기와 'yield'
키워드를 사용하여 Python 방식으로이 문제를 해결했습니다.
- @vartec은 위의 생성기와 'yield'
- 모든 STDOUT 행을 인쇄합니다 ( STDOUT 버퍼를 완전히 읽을 수 있기 전에 프로세스가 종료 된 경우에도 ).
- 고주파로 프로세스를 폴링하는 CPU 사이클을 낭비하지 마십시오.
- 하위 프로세스의 반환 코드 확인
- 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)
여러 파일에 대해 셸 명령을 실행해야하는 경우이 방법이 도움이되었습니다.
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의 솔루션을 보았습니다. 앞서 가서 그것을 통합했습니다.
에 대한 초기 명령을 분할하는 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...'
@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에서 명령을 실행하는 것과 똑같이 작동합니다.
subprocess
python 모듈 을 사용하면 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
예 : 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 ""
The output can be redirected to a text file and then read it back.
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))
참고URL : https://stackoverflow.com/questions/4760215/running-shell-command-and-capturing-the-output
'program tip' 카테고리의 다른 글
.First를 언제 사용하고 .FirstOrDefault를 LINQ와 함께 사용합니까? (0) | 2020.09.29 |
---|---|
중첩 된 객체, 배열 또는 JSON에 액세스하고 처리하려면 어떻게해야합니까? (0) | 2020.09.29 |
이름으로 데이터 프레임 열 삭제 (0) | 2020.09.29 |
TextView 스타일 설정 (굵게 또는 기울임 꼴) (0) | 2020.09.29 |
정수를 합산하는 쉘 명령, 한 줄에 하나씩? (0) | 2020.09.29 |