Python 调用执行Shell命令

  1. os.system
  2. subprocess
    1. run
    2. getoutput
    3. Popen
  3. 在权限不足的时候如何使用 sudo
    1. 直接执行
    2. 后台执行

os.system

os.system(cmd)

可以直接使用Shell命令,并回显。

subprocess

subprocess模块允许启动一个新的进程,并连接到输入/输出/错误管道,从而获取返回值。

常用的方法有

run

subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, capture_output=False, shell=False, cwd=None, timeout=None, check=False, encoding=None, errors=None, text=None, env=None, universal_newlines=None)
参数 注释
args 必须使用数组的方式,所以经常使用shlex.split()来切割命令
stdin 标准输入
input 使用字节传递输入,如果text为True则可以为字符串
stdout 标准输出
stderr 标准错误输出
capture_output 是否获取返回值
shell 执行指定的shell指令, args可以直接为字符串
cwd 指定运行的目录
timeout 超时后杀死子进程并抛出 TimeoutExpired 异常
check 进程以非零码退出时,抛出 CalledProcessError 异常
encoding 指定编码,此时input可以为字符串
errors 输出文本
text 以 input 和 errors 输出文本
env dict 类型,提供环境变量
universal_newlines 等同于 text 参数,输出字符串,否则输出字节

例如:

subprocess.run(shlex.split("tmux new-session -s TireFire_{} -n Main -c {} -d".format(hostname, cwd)))

此时只是启动一个新进程执行,并没有捕获输出

subprocess.run(shell.split("ls -la"), capture_output=True, encoding='utf-8')

这样就可以再返回值里面获得stdout

更简单的方式是使用subprocess.getoutput

getoutput

subprocess.getoutput(cmd)

例子:

uid = subprocess.getoutput("id -u")
if uid != "0":
    print("must be run with root permissions")

Popen

subprocess.Popen是基础API命令,可以控制的地方也相对多一些

stdin=subprocess.PIPE的时候, 可以通过proc.stdout获取内容

proc.wait()等待进程结束

比如需要同时输出屏幕和文件的时候

import subprocess, sys
proc = subprocess.Popen(shell,
                        shell=True,
                        stdout=subprocess.PIPE if output else None,
                        stderr=subprocess.STDOUT if output else None,
                        universal_newlines=True)
if output:
    for line in proc.stdout:
        sys.stdout.write(line)
        output.write(line)
proc.wait()

在权限不足的时候如何使用 sudo

这个分两种情况,一种是直接执行,另外一种是希望后台另起进程执行。参考这篇文章

直接执行

subprocess.run(shlex.split(f"sudo -S {shell}"),
                shell=False)

这样就会提示需要 sudo 密码

后台执行

passwd = getpass("Please enter your password: ")
passwd_proc = subprocess.Popen(shlex.split(
    f"echo {passwd}"), stdout=subprocess.PIPE)

subprocess.Popen(shlex.split(f"sudo -S {shell}" if sudo else shell), shell=False, stdin=passwd_proc.stdout, stdout=output, stderr=output)

这种方式稍微绕一下,但是效果很好。


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 365433079@qq.com