本文总结使用 shell
脚本的几种方法。
Updated: 2022 / 7 / 27
Python | 执行shell脚本的几种方法
- 总览
- 方法
-
- os
- Subprocess
- sh
- 参考链接
总览
Python
作为一门脚本语言,有时候需要与 shell
命令交互式使用,在 Python
中提供了很多的方法可以调用并执行 shell
脚本,本文做一个简单的总结 1。
本文的开发环境是 macOS Big Sur
。
方法
os
-
os.system('command')
这是python
自带的执行shell
命令的方法,其中最后一个0
是这个命令的返回值,为0
表示命令执行成功。
但是使用system()
无法将执行的结果保存起来,如下所示:
print(os.system("touch a.txt"))
# 0
# <class 'int'>
# 会返回一个 0,表示执行成功了,然后在当前文件夹之下创建了一个新的 a.txt 文件
print(os.system("ls -lh"))
# total 416
# -rw-r--r-- 1 staff 49B Jul 27 20:02 main.py
# -rw-r--r-- 1 staff 63B Jul 16 17:38 temporary.py
# -rw-r--r-- 1 staff 4.1K Jul 24 20:02 test.py
# -rw-r--r-- 1 staff 94B Jul 24 19:31 usrs_info.pickle
# 0
#
# <class 'int'>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
-
os.popen('command')
通过os.popen()
返回的是一个文件对象,对其进行读取read()
的操作可以看到执行的输出。
f = os.popen("ls -l")
# 返回的是一个文件对象
print(f.read())
# 通过文件的read()读取所返回的内容
# <class 'str'>
#
# total 416
# -rw-r--r-- 1 staff 49B Jul 27 20:02 main.py
# -rw-r--r-- 1 staff 63B Jul 16 17:38 temporary.py
# -rw-r--r-- 1 staff 4.1K Jul 24 20:02 test.py
# -rw-r--r-- 1 staff 94B Jul 24 19:31 usrs_info.pickle
f = os.popen("touch b.txt")
# 创建一个文件
print(f.read())
# 无返回值
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
Subprocess
subprocess
模块是 python
从 2.4
版本开始引入的模块,也是系统自带的,不需要再额外安装了。
主要用来取代一些旧的模块方法,如 os.system
、os.spawn*
、os.popen*
、commands.*
等。
subprocess
通过子进程来执行外部指令,并通过 input / output / error
管道,获取子进程的执行的返回信息。
subprocess.call()
执行命令,并返回执行状态。其中,
shell
参数为False
时,命令以及命令的参数需要通过列表的方式传入;
print(subprocess.call(["ls", "-l"], shell=False))
# <class 'int'>
#
# total 416
# -rw-r--r-- 1 staff 49B Jul 27 20:02 main.py
# -rw-r--r-- 1 staff 63B Jul 16 17:38 temporary.py
# -rw-r--r-- 1 staff 4.1K Jul 24 20:02 test.py
# -rw-r--r-- 1 staff 94B Jul 24 19:31 usrs_info.pickle
# 0
print(subprocess.call(["touch", "c.txt"], shell=False))
# 直接返回 0,表示操作成功
# 0
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
shell
参数为True
时,可通过一个字符串直接传入命令以及命令所需要的参数;
print(subprocess.call(("ls -l"), shell=True)
# <class 'int'>
#
# total 416
# -rw-r--r-- 1 staff 49B Jul 27 20:02 main.py
# -rw-r--r-- 1 staff 63B Jul 16 17:38 temporary.py
# -rw-r--r-- 1 staff 4.1K Jul 24 20:02 test.py
# -rw-r--r-- 1 staff 94B Jul 24 19:31 usrs_info.pickle
# 0
print(subprocess.call(["mkdir newdir1"], shell=True))
# 直接返回 0,表示操作成功
# 0
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
subprocess.check_call()
用法与subprocess.call()
类似,区别是,
当返回值不为0
时,直接抛出异常。
subprocess.check_output()
用法与上面两个方法类似,区别是,
当返回值为0
时,直接返回输出结果;
当返回值不为0
,直接抛出异常。
需要说明的是,该方法在python3.x
中才有。
a = subprocess.check_output(["ls","-l"], shell=False)
print(a)
# <class 'bytes'>
# 不是直接返回0了,而是直接返回执行结果的内容
# b'total 416\n-rw-r--r-- 1 xueshanzhang staff 4326 Jul 24 17:59 MotivationLetterGenerator.py\ndrwxr
- 1
- 2
- 3
- 4
- 5
subprocess
的功能还有更多,比如还有 Popen
类。
subprocess
模块中定义了一个 Popen
类,通过它可以来创建进程,并与其进行复杂的交互。
sh
首先安装 sh
库,pip install sh
。
Python
是一种伟大的脚本语言,不过有时使用标准 os
和 subprocess
库会有点棘手。
sh
库提供了一种不错的替代方案。sh
库:http://amoffat.github.io/sh/
库允许用户像使用普通函数一样调用任意程序,这对自动化工作流和任务非常有用。
它的一般工作模式如下:
sh.command_name("参数一", "参数二", "参数三")
- 1
如下,
print(sh.pwd())
# /Users/PycharmProjects/pythonProject0312
sh.mkdir('FolderA')
sh.touch('File.txt')
print(sh.whoami())
# your username
#
# <class 'sh.RunningCommand'>
print(sh.echo('This is great!'))
# This is great!
#
# <class 'sh.RunningCommand'>
sh.ls("-l")
# 等价于 ls -l
print(sh.ls("-l"))
# total 416
# -rw-r--r-- 1 staff 49B Jul 27 20:02 main.py
# -rw-r--r-- 1 staff 63B Jul 16 17:38 temporary.py
# -rw-r--r-- 1 staff 4.1K Jul 24 20:02 test.py
# -rw-r--r-- 1 staff 94B Jul 24 19:31 usrs_info.pickle
sh.df("-h")
# 等价于 df -h
print(sh.df("-h"))
# Filesystem Size Used Avail Capacity iused ifree %iused Mounted on
# /dev/disk3s1s1 228Gi 21Gi 31Gi 41% 553757 2393071203 0% /
# devfs 204Ki 204Ki 0Bi 100% 705 0 100% /dev
# ...
#
# <class 'sh.RunningCommand'>
sh.du("-h", "-d 1")
# 等价于 du -h -d 1
print(sh.du("-h", "-d 1"))
# 当有多个参数的情况,且参数可以赋值
# 0B ./FolderA
# 92K ./.git
# 40K ./.idea
# 340K .
#
# <class 'sh.RunningCommand'>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
注意:上面在通过 sh.**
编写的时候可能没有代码提示,因为 sh
模块里面并没有直接定义像上面的 pwd()
,touch()
,du()
等这些函数,他是通过其他的方式实现的,所以没有智能敏感提示。
参考链接
-
python执行shell脚本的几种方法 ↩︎