os.system()、os.popen()和subprocess的区别

一.优势与区别

  1. os.system():
    功能: 执行系统命令并返回命令的退出状态。
    实现: 调用操作系统的命令解释器来执行命令。
    限制: 不能捕获命令的输出,适用于简单的命令执行。

  2. os.popen():
    功能: 执行系统命令并打开一个管道,可以读取或写入命令的输入输出。
    实现: 创建一个子进程来执行命令,并通过管道与子进程通信。
    优势: 可以捕获命令的输出,适用于需要处理命令输出的情况。

  3. subprocess:
    功能: 提供更强大的接口来创建和管理子进程,替代 os.system() 和 os.popen()。
    实现: 使用 subprocess.run(), subprocess.call(), subprocess.Popen() 等方法来执行命令。
    优势: 更灵活,可以控制子进程的输入、输出和错误流,适用于复杂的命令执行和进程管理。

二.具体实现代码

  • os.system()
  • os.system方法是os模块最基础的方法,其它的方法一般在该方法基础上封装完成。
    os.system()的返回值是脚本的退出状态码,0表示成功,其他均为失败

system函数可以将字符串转化成命令在服务器上运行;其原理是每一条system函数执行时,其会创建一个子进程在系统上执行命令行,子进程的执行结果无法影响主进程。
但是上述原理会导致当需要执行多条命令行的时候可能得不到预期的结果:

import os
os.system('cd /usr/local')os.mkdir('aaa.txt)

上述程序运行后会发现txt文件夹并没有创建在/usr/local文件夹下,而是在当前的目录下。
因此为了保证system执行多条命令可以成功,多条命令需要在同一个子进程中运行:

import os
os.system('cd /usr/local && mkdir aaa.txt')# 或者os.system('cd /usr/local ; mkdir aaa.txt')
  • os.popen() 方法用于从一个命令打开一个管道,在Unix,Windows中有效。
#!/usr/bin/python3
import os, sys
# 使用 mkdir 命令
a = 'mkdir nwdir'
b = os.popen(a,'r',1)
print (b)

执行以上程序输出结果为:

open file 'mkdir nwdir', mode 'r' at 0x81614d0
  • subprocess.run() 是 subprocess 模块中最简单直接的一个函数,它用于执行一个命令并等待其完成。这个函数返回一个 CompletedProcess 对象,其中包含了执行结果的各种信息,如返回码、标准输出和标准错误等
import subprocess

result = subprocess.run(['ls', '-l'], capture_output=True, text=True)
print(result.stdout)  # 输出命令执行结果
print(result.returncode)  # 输出命令返回值

  • 虽然 subprocess.run() 函数非常方便,但它只适用于执行一次命令并等待其完成的情况。如果需要与子进程进行更复杂的交互,比如读取其输出、向其发送输入,或者同时管理多个子进程,那么就需要使用 subprocess.Popen() 类
import subprocess

# 使用管道连接多条命令
command = "echo 'Hello, World!' && ls -l && pwd"

# 创建子进程并执行命令
process = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)

# 获取输出和错误信息
stdout, stderr = process.communicate()

# 打印输出和错误信息
print("Output:\n", stdout)
print("Error:\n", stderr)

默认情况下,subprocess 模块创建的子进程会将其输出以通过索引来获取我们需要的部分。在这个例子中,我们只关心标准输出,所以使用了 _ 来忽略标准错误。

值得注意的是,communicate() 方法会阻塞当前进程,直到子进程结束为止。这意味着,如果你的子进程是一个长时间运行的进程,那么 communicate() 会导致你的 Python 脚本一直等待下去,直到子进程完成。因此,在使用 communicate() 时,需要谨慎考虑是否适合你的应用场景。

除了 communicate() 方法外,Popen 对象还提供了许多其他方法和属性,可以用于更精细地控制子进程的行为。
例如,你可以使用 stdin、stdout 和 stderr 属性来获取或设置子进程的输入/输出/错误管道;使用 poll() 方法来检查子进程是否已结束;使用 kill() 或 terminate() 方法来强制结束子进程等。

import subprocess

# 创建子进程
process = subprocess.Popen(['sleep', '10'])

# 检查子进程是否完成
while process.poll() is None:
    print("子进程仍在运行...")
    # 可以在这里执行其他操作

print("子进程已完成")

三.调用Shell脚本

假定有一个shell脚本test.sh:

echo 'hello python!'
echo 'hello world!'
exit 1

os.system的执行结果

>>> import os
>>> os.system("./test.sh")
hello python!
hello world!
256
>>> n=os.system("./test.sh")
hello python!
hello world!
>>> n
256
>>> n>>8
1

os.popen()执行结果

>>> import os
>>> os.popen("./test.sh")
<open file './test.sh', mode 'r' at 0x7f6cbbbee4b0>
>>> f=os.popen("./test.sh")
>>> f
<open file './test.sh', mode 'r' at 0x7f6cbbbee540>
>>> f.readlines()
['hello python!\n', 'hello world!\n']

PS:

  1. os.popen() 返回值是文件对象
    注意:返回值是文件对象,既然是文件对象,使用完就应该关闭
    正确使用方法,不需要显式的写p.close()
with os.popen(command, "r") as p:
     r = p.read()
  1. os.popen() 非阻塞
import os
os.popen(r"D:\Program Files (x86)\Tencent\QQ\Bin\QQScLauncher.exe")
print("test")

从上面实例可知,os.popen执行打开QQScLauncher.exe这个工具,但从实际执行结果看,QQScLauncher.exe还没打开,就直接进入了下一条语句,打印了"test"

想使用os.popen() 变阻塞,使用read()或readlines()对命令结果进行读,由此产生了阻塞的效果

import os
ret = os.popen("ping 127.0.0.1 -t")
ret.readlines()

关于阻塞调用
1.os.popen
该命令会先创建一个管道,然后fork一个子进程,关闭管道的一端,执行exec,最后返回一个标准的io文件指针。
popen本身是不阻塞的,要通过标准io的读取使它阻塞

2.os.system
system相当于是先后调用了fork, exec,waitpid来执行外部命令
system本身就是阻塞的

参考资料:
os.system()、os.popen()和subprocess的区别(一)
关于os.system和os.popen的坑
Python 的 subprocess 介绍及如何使用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值