Python中调用Linux命令并获取返回值

 方法一、使用os模块的system方法

os.system(cmd),只返回状态码,os.system(cmd)会启动子进程,在子进程中执行cmd,如果cmd有执行内容,会在标准输出显示。

这个调用相当直接,且是同步进行的,程序需要阻塞并等待返回。返回值是依赖于系统的,直接返回系统的调用返回值,所以windows和linux是不一样的。
在linux中其返回值是shell指令运行后返回的状态码,int类型,0表示shell指令成功执行,256/512表示未找到,该方法适用于shell命令不需要输出内容的场景

举例说明:

# 列举当前目录下的所有文件
import
os val = os.system('ls -al') print val #输出为0 val = os.system('ls -al non_exist_folder') print val #输出为512 val = os.system('ls -al|grep non_exist_val') print val #输出为256

方法二、使用os.popen()

只返回信息该方法以文件的形式返回shell指令运行后的结果需要获取内容时可使用read()或readlines()方法。

参考:https://blog.csdn.net/xc_zhou/java/article/details/96445422

os.popen(command[,mode[,bufsize]])
  • mode – 模式权限可以是 ‘r’(默认) 或 ‘w’。
  • bufsize – 指明了文件需要的缓冲大小
    • 0意味着无缓冲;1意味着行缓冲;
    • 其它正值表示使用参数大小的缓冲(大概值,以字节为单位)。
    • 负的bufsize意味着使用系统的默认值,一般来说,对于tty设备,它是行缓冲;对于其它文件,它是全缓冲。如果没有改参数,使用系统的默认值。
os.popen执行命令是非阻塞的,也就是说不等cmd命令执行完毕就继续下面的代码,但为了能够获取到命令执行结果,可以使用read()或readlines()对命令的执行结果进行读操作,由此产生了阻塞的效果。但是,如果你的命令执行无法退出或进入交互模式,这种“读”将形成完全阻塞的情况,表现的像程序卡住了。
popen方法通过p.read()获取终端输出,而且popen需要关闭close()。当执行成功时,close()不返回任何值,失败时,close()返回系统返回值。可见它获取返回值的方式和os.system不同。

举栗: 

>>> import os
>>> p=os.popen('ls ./')
>>> p.read()    #使用read()获取到一个字符串
'generate_charts_by_testIds_610.py\ngenerate_charts_by_testIds_modify.py\npsnr_bitrate.pdf\nssim_bitrate.pdf\n'
>>> p.read()    #第二次读取为空
''
>>> p=os.popen('ls ./')
>>> p.readlines()   #使用readlines()获取到一个list
['generate_charts_by_testIds_610.py\n', 'generate_charts_by_testIds_modify.py\n', 'psnr_bitrate.pdf\n', 'ssim_bitrate.pdf\n']
>>>
>>> p     #使用popen返回的是文件对象,既然是文件对象,使用完就应该关闭
<open file 'ls ./', mode 'r' at 0x7f16581afd20>    
>>> p.close()
>>>
>>> p
<closed file 'ls ./', mode 'r' at 0x7f16581afd20>
>>>
>>> with os.popen('ls ./') as aa:    #使用with语句,就不需要显式的写p.close()
...     r=aa.read()
...
>>> aa
<closed file 'ls ./', mode 'r' at 0x7f16581afc90>
>>>
>>> r
'generate_charts_by_testIds_610.py\ngenerate_charts_by_testIds_modify.py\npsnr_bitrate.pdf\nssim_bitrate.pdf\n'
>>>
>>>val=os.popen('ls -al')
>>>for i in val.readlines():
       print i 

方法三、使用commands模块(在Python3.0中移除)

有三个方法可以使用:

(1)commands.getstatusoutput(cmd),其以元组(status,output)的形式返回命令执行后的返回状态和执行结果。其中,对cmd的执行实际上是按照{cmd;} 2>&1的方式,所以output中包含控制台输出信息或者错误信息,output中不包含尾部的换行符。

(2)commands.getoutput(cmd),返回cmd的输出结果。

(3)commands.getstatus(file),返回ls -l file的执行结果字符串,调用了getoutput,不建议使用此方法

import commands
aa=commands.getstatusoutput('ls -l')
输出:(0, 'total 0\n-rw-rw-r-- 1 roaddb roaddb 0 Dec 11 10:09 a.txt\n-rw-rw-r-- 1 roaddb roaddb 0 Dec 11 10:09 b.txt') 
#返回一个元组,对比os.popen(cmd)的返回结果,发现output中不包含尾部的换行符
bb=commands.getoutput('ls -l') #只返回执行结果 输出:'total 0\n-rw-rw-r-- 1 roaddb roaddb 0 Dec 11 10:09 a.txt\n-rw-rw-r-- 1 roaddb roaddb 0 Dec 11 10:09 b.txt'
cc=commands.getstatus('a.txt') #查询某个文件的状态 输出:'-rw-rw-r-- 1 roaddb roaddb 0 Dec 11 10:09 a.txt'
dd=commands.getstatusoutput('ls -l non_exist_folder') #执行结果中包含控制台输出信息或者错误信息 输出:(512, "ls: cannot access 'non_exist_folder': No such file or directory")

os.popen(cmd)返回的是一个类文件对象,commands.getoutput(cmd)返回了字符串类型的输出结果,很多情况下用起来要更方便些。

方法四、subprocess模块

允许创建很多子进程,创建的时候能指定子进程和子进程的输入、输出、错误输出管道,执行后能获取输出结果和执行状态。

(1)subprocess.call():执行指定的命令, 返回命令执行状态,0或者非0, 功能类似os.system(cmd)

>>> res = subprocess.call(["ls","-l"])
总用量 28
-rw-r--r-- 1 root root   0 6月 16 10:28 1
drwxr-xr-x 2 root root 4096 6月 22 17:48 _1748
-rw-------. 1 root root 1264 4月 28 20:51 anaconda-ks.cfg
drwxr-xr-x 2 root root 4096 5月 25 14:45 monitor
-rw-r--r-- 1 root root 13160 5月  9 13:36 npm-debug.log

>>> res   # 命令执行状态
0

(2)subprocess.check_call()python2.5中新增的函数, 执行指定的命令, 如果执行成功则返回状态码, 否则抛出异常,可用try…except…来检查

>>> ret=subprocess.check_call(["ls","-l","vpu_deamon.log"])
-rw-rw-r-- 1 ubuser ubuser 8784 Nov 11  2020 vpu_deamon.log
>>> ret
0
>>>
>>> ret=subprocess.check_call(["ls","-l",".log"])
ls: cannot access '.log': No such file or directory
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/subprocess.py", line 541, in check_call
    raise CalledProcessError(retcode, cmd)
subprocess.CalledProcessError: Command '['ls', '-l', '.log']' returned non-zero exit status 2

(3)subprocess.check_output():接受字符串形式的命令,返回执行结果,python 2中返回字符串,python 3中返回字节形式的结果。失败则抛出异常,可用try…except…来检查

#python 2.7
>>> res = subprocess.check_output("pwd")
>>> res
'/home/ubuser\n'
>>> type(res)
<type 'str'>

#python 3.5.2
>>> res = subprocess.check_output("pwd")
>>> res
b'/home/ubuser\n'
>>> type(res)
<class 'bytes'>

 

(4)subprocess.run()python3.5中新增的函数, 执行指定的命令, 等待命令执行完成后返回一个包含执行结果的CompletedProcess类的实例。

>>> import subprocess
>>> subprocess.run(["df","-h"]) # python 解析则传入命令的每个参数的列表
Filesystem      Size Used Avail Use% Mounted on
/dev/mapper/VolGroup-LogVol00
           289G  70G 204G 26% /
tmpfs         64G   0  64G  0% /dev/shm
/dev/sda1       283M  27M 241M 11% /boot
CompletedProcess(args=['df', '-h'], returncode=0)

>>> subprocess.run("df -h|grep /dev/sda1",shell=True)  # 需要交给Linux shell自己解析,则:传入命令字符串,shell=True
/dev/sda1       283M  27M 241M 11% /boot
CompletedProcess(args='df -h|grep /dev/sda1', returncode=0)

(4)subprocess.getstatusoutput()python3中可用,接受字符串形式的命令,返回一个元组形式的结果,第一个元素是命令执行状态,第二个为执行结果

>>> subprocess.getstatusoutput('pwd')
(0, '/root')

>>> subprocess.getstatusoutput('pd')
(127, '/bin/sh: pd: command not found')

(5)subprocess.getoutput()python3中可用,接受字符串形式的命令,返回执行结果

>>> subprocess.getoutput('pwd')
'/root'

 (7)subprocess.Popen():其实以上subprocess使用的方法,都是对subprocess.Popen的封装

class Popen(args, bufsize=0, executable=None, stdin=None, stdout=None, stderr=None, preexec_fn=None, close_fds=False, shell=False, cwd=None, env=None, universal_newlines=False, startupinfo=None, creationflags=0),Popen对象创建后,主程序不会自动等待子进程完成。我们必须调用对象的wait()方法,父进程才会等待 (也就是阻塞block)

 1)stdout =subprocess.PIPE 与 stderr=subprocess.PIPE ,python 2中返回字符串,python 3中返回字节形式的结果

#python 3
>>> res = subprocess.Popen("ls /tmp/", shell=True, stdout=subprocess.PIPE) # 使用管道 >>> res.stdout.read() # 标准输出 b'/tmp/yum.log\n' res.stdout.close() # 关闭 >>> >>> res = subprocess.Popen("lm -l",shell=True,stdout=subprocess.PIPE,stderr=subprocess.PIPE)# 标准输出为空 >>> res.stdout.read() b''#标准错误中有错误信息 >>> res.stderr.read() b'/bin/sh: lm: command not found\n'

2)poll() 定时检查命令有没有执行完毕,执行完毕后返回执行结果的状态,没有执行完毕返回None

3)wait()等待命令执行完成,并且返回结果状态

4)  terminate() 结束进程

5)pid 获取当前执行子shell的程序的进程号

说明:subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, shell=False, timeout=None, check=False, universal_newlines=False)

     subprocess.call(args, *, stdin=None, stdout=None, stderr=None, shell=False, timeout=None)

     subprocess.check_call(args, *, stdin=None, stdout=None, stderr=None, shell=False, timeout=None)

    args:表示shell指令,若以字符串形式给出shell指令,如"ls -l "则需要使shell = Ture。否则默认以数组形式表示shell变量,如"ls","-l"。

    当使用比较复杂的shell语句时,可以先使用shlex模块的shlex.split()方法来帮助格式化命令,然后在传递给run()方法或Popen。

subprocess.run()、subprocess.call()、subprocess.check_call()、subprocess.check_output()都是通过对subprocess.Popen的封装来实现的高级函数,因此如果我们需要更复杂功能时,可以通过subprocess.Popen来完成

使用举栗:

import shlex
import subprocess
command='ls -l'
args=shlex.split('ls -l')
bb=subprocess.Popen(args) #bb是一个Popen的对象,该对象不能通过read()或readlines()来读取
输出:total 0
-rw-rw-r-- 1 roaddb roaddb 0 Dec 11 10:09 a.txt
-rw-rw-r-- 1 roaddb roaddb 0 Dec 11 10:09 b.txt #在该处需要点击换行符才会结束
aa=subprocess.call('ls -l',shell=True)  #其返回值为shell命令的执行返回码
输出:total 0
-rw-rw-r-- 1 roaddb roaddb 0 Dec 11 10:09 a.txt
-rw-rw-r-- 1 roaddb roaddb 0 Dec 11 10:09 b.txt #直接返回

 后续还需要继续学习:https://www.cnblogs.com/lincappu/p/8270709.html

在Python3中的情况

期望:想要在Python3中执行curl命令并返回执行结果,返回结果时json体

分析:

cmd='curl -s "http://127.0.0.1:8080/xxxxx"' 

1)使用os.system(cmd) 无法获取输出内容

2)使用os.popen(cmd).read()可以获取到返回的json体${aa},通过json.loads(${aa})可以将json体转为字典样式

3)commands模块在Python3.0中被废弃了

4)subprocess.getstatusoutput(cmd)输出结果类似于python2中的commands.getstatusoutput(cmd),返回一个元组,元组的第2个值是执行结果${aa},通过json.loads(${aa})可以将json体转为字典样式。

参考:https://www.cnblogs.com/pengpp/p/9833349.html

     https://www.jb51.net/article/142787.htm

 

posted @ 2019-12-11 19:00  声声慢43  阅读(37441)  评论(0编辑  收藏  举报