有时候我们需要从Python中执行Linux命令,下面就介绍几种方法?
1. os 模块:
1.1 os.system 函数:
system方法会创建子进程运行外部程序,方法只返回外部程序的运行结果。这个方法比较适用于外部程序没有输出结果的情况。
>>> os.system('echo \ "Hello World\"') # 直接使用os.system调用一个echo命令 Hello World 0 >>> os.system("cat /proc/meminfo") MemTotal: 486640 kB MemFree: 301184 kB Buffers: 10304 kB Cached: 58316 kB SwapCached: 0 kB Active: 43748 kB Inactive: 45336 kB Active(anon): 20476 kB Inactive(anon): 520 kB Active(file): 23272 kB Inactive(file): 44816 kB
注意:上面说了,此方法只会外部程序的结果,也就是os.system的结果,所以如果你想接收命令的返回值,接着向下看
1.2 os模块的popen方法
当需要得到外部程序的输出结果时,本方法非常有用,返回一个类文件对象,调用该对象的read()或readlines()方法可以读取输出内容。
>>> print(os.popen('ls -lt')) # 是以一个类文件对象的形式
<os._wrap_close object at 0x7efeaa61bdd8>
>>> print(os.popen('ls -lt').read())
总用量 98 drwxr-xr-x. 2 root root 4096 5月 19 04:26 opt dr-xr-x---. 3 root root 4096 5月 19 04:26 root drwxr-xr-x. 19 root root 3760 5月 19 04:22 dev drwxr-xr-x. 78 root root 4096 5月 19 04:22 etc drwxrwxrwt. 7 root root 4096 5月 19 04:22 tmp >>> print(os.popen('ls -lt').readlines()) readlines() 是以列表的形式打印出来
2. commands 模块(在Python2.X中纯在Python3中就移除了,在Python 3.X 中 被 sudprocess 取代,这里就不怎么介绍commands模块了)
使用commands模块的getoutput方法,这种方法同popend的区别在于popen返回的是一个类文件对象,而本方法将外部程序的输出结果当作字符串返回,很多情况下用起来要更方便些。
主要方法:
* commands.getstatusoutput(cmd) 返回(status, output)
* commands.getoutput(cmd) 只返回输出结果
* commands.getstatus(file) 返回ls -ld file的执行结果字符串,调用了getoutput,不建议使用此方法
3. subprocess 模块
官方文档: https://docs.python.org/3/library/subprocess.html
subprocess模块用于取代上面这些模块。ubprocess与system相比的优势是它更灵活(你可以得到标准输出,标准错误,“真正”的状态代码,更好的错误处理,等..)。我认为使用os.system已过时,或即将过时。
3.1 call 执行命令,返回状态码(命令正常执行返回0,报错则返回1)
1 >>> ret = subprocess.call('df -h', shell='True') 2 Filesystem Size Used Avail Use% Mounted on 3 /dev/mapper/VolGroup-lv_root 4 18G 1.7G 15G 10% / 5 tmpfs 238M 0 238M 0% /dev/shm 6 /dev/sda1 477M 38M 414M 9% /boot 7 8 #两种不同的写法 9 10 >>> ret = subprocess.call(["ls", "-l"], shell=False) #shell为False的时候命令必须分开写 11 总用量 24 12 -rw-------. 1 root root 1068 8月 28 2018 anaconda-ks.cfg 13 -rw-r--r--. 1 root root 14484 8月 28 2018 install.log 14 -rw-r--r--. 1 root root 3482 8月 28 2018 install.log.syslog
>>> print(ret)
0
3.2 check_call 执行命令,如果执行成功则返回状态码0,否则抛异常
1 >>> ret = subprocess.check_call(['ls', '-l'], shell='False') 2 anaconda-ks.cfg install.log install.log.syslog 3 >>> print(ret) 4 0 5 6 >>> ret = subprocess.check_call('ls -l', shell='True') 7 总用量 24 8 -rw-------. 1 root root 1068 8月 28 2018 anaconda-ks.cfg 9 -rw-r--r--. 1 root root 14484 8月 28 2018 install.log 10 -rw-r--r--. 1 root root 3482 8月 28 2018 install.log.syslog
3.3 check_output 执行命令,如果执行成功则返回执行结果,否则抛异常。
>>> subprocess.check_output(['echo', "Hello, Word"]) b'Hello, Word\n' >>> subprocess.check_output('ls -l', shell='True') b'\xe6\x80\xbb\xe7\x94\xa8\xe9\x87\x8f 24\n-rw-------. 1 root root 1068 8\xe6\x9c\x88 28 2018 anaconda-ks.cfg\n-rw-r--r--. 1 root root 14484 8\xe6\x9c\x88 28 2018 install.log\n-rw-r--r--. 1 root root 3482 8\xe6\x9c\x88 28 2018 install.log.syslog\n'
返回结果为bays 类型, 不怎么常用这个
subprocess 模块 在Python3版本新加功能:(常用)
简要说明: 有需要用到python调用外部程序命令的同学们, 那么你们请一定选择subprocess库,它给我们工作带来极大的方便也许我这么解释不正确, 还是用官方的话来说吧 <subporcess 模块允许你产生新的进程,并且可以把输入,输出, 错误 直接连接到管道,最后获取结果,python也有俩个比较功能不是那么太全的内置模块<os.system, os.spawn..>等这些。
subprocess.run()方法. 此方法作用: 使用参数运行命令并返回完整的进程实例
subprocess.run(*popenargs, input=None, timeout=None, check=False, **kwargs)
实例:
1 >>> subprocess.run(['ls', '-l']) # 注意 用[] 括号包着你要执行的命令,后面也可以跟路径 #相当于在系统中执行ls -l / 命令
2 总用量 24 3 -rw-------. 1 root root 1068 8月 28 2018 anaconda-ks.cfg 4 -rw-r--r--. 1 root root 14484 8月 28 2018 install.log 5 -rw-r--r--. 1 root root 3482 8月 28 2018 install.log.syslog 6 CompletedProcess(args=['ls', '-l'], returncode=0) 7 >>> subprocess.run(['ls', '-l' , '/']) # 这是跟路径的 查看的是根下的 8 总用量 98 9 dr-xr-xr-x. 2 root root 4096 8月 28 2018 bin 10 dr-xr-xr-x. 5 root root 1024 8月 29 2018 boot 11 drwxr-xr-x. 19 root root 3760 5月 20 04:06 dev 12 drwxr-xr-x. 78 root root 4096 5月 20 04:06 etc 13 drwxr-xr-x. 2 root root 4096 6月 28 2011 home 14 dr-xr-xr-x. 8 root root 4096 8月 29 2018 lib 15 dr-xr-xr-x. 9 root root 12288 4月 26 08:08 lib64 16 drwx------. 2 root root 16384 8月 28 2018 lost+found
Popen
实际上,我们上面的三个函数都是基于Popen()的封装(wrapper)。这些封装的目的在于让我们容易使用子进程。当我们想要更个性化我们的需求的时候,就要转向Popen类,该类生成的对象用来代表子进程。
与上面的封装不同,Popen对象创建后,主程序不会自动等待子进程完成。我们必须调用对象的wait()方法,父进程才会等待 (也就是阻塞block):
[root@localhost opt]# vim 1.py #!/etc/svn/python import subprocess import subprocess child = subprocess.Popen(["ping","-c","5","127.0.0.1"]) print("parent 进程")
[root@localhost opt]# python3 1.py
结果: parent 进程 #父进程没有等子进程结束 直接执行的父进程 在执行的子进程 [root@localhost opt]# PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data. 64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.023 ms 64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.030 ms 64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.030 ms 64 bytes from 127.0.0.1: icmp_seq=4 ttl=64 time=0.030 ms 64 bytes from 127.0.0.1: icmp_seq=5 ttl=64 time=0.031 ms --- 127.0.0.1 ping statistics --- 5 packets transmitted, 5 received, 0% packet loss, time 4000ms
对于等待的情况:
1 import subprocess 2 child = subprocess.Popen(["ping","-c","5","www.google.com"]) 3 child.wait() 4 print("parent process")
此外,你还可以在父进程中对子进程进行其它操作,比如我们上面例子中的child对象:
child.poll() # 检查子进程状态
child.kill() # 终止子进程
child.wait() # 等待子进程结束
child.send_signal() # 向子进程发送信号
child.terminate() # 终止子进程
子进程的PID存储在child.pid
stdin标准输入, stdout 标准输出, stderr 标准错误:
我们可以在Popen()建立子进程的时候改变标准输入、标准输出和标准错误,并可以利用subprocess.PIPE将多个子进程的输入和输出连接在一起,构成管道(pipe):
import subprocess a = subprocess.Popen(["ls","-l"], stdout=subprocess.PIPE) b = subprocess.Popen(["wc"], stdin=a.stdout,stdout=subprocess.PIPE) out = b.communicate() # 是Popen对象的一个方法,该方法会阻塞父进程,直到子进程完成 print(out)
结果:
[root@localhost opt]# python3 test.py
(b' 3 20 117\n', None)
subprocess.PIPE实际上为文本流提供一个缓存区。a的stdout将文本输出到缓存区,随后b的stdin从该PIPE中将文本读取走。b的输出文本也被存放在PIPE中,直到communicate()方法从PIPE中读取出PIPE中的文本。
要注意的是,communicate()是Popen对象的一个方法,该方法会阻塞父进程,直到子进程完成。