常见Python中调用Linux命令

隐身守侯 提交于 2019-12-29 07:26:43

有时候我们需要从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对象的一个方法,该方法会阻塞父进程,直到子进程完成。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!