python环境下运行bash命令

一、前言

最近在写程序时遇到一个问题:即需要同时运行python代码和bash代码。本质来说,仅用bash脚本是可以实现的,但是程序涉及到向量、矩阵的运算,并且逻辑判断较为复杂,只使用bash脚本来实现会变得非常麻烦,同时仅仅使用python也是不行的,因为程序是在Linux超算上使用的,一些文本处理、文件(夹)操作以及提交作业都是bash语句更为方便,因此这里自然就需要能够同时使用bash命令和python代码。当然比较简单的想法就是将bash脚本作为主体,python文件作为中间过程调用的函数,来处理数据,它们之间通过字符串或文件来传输中间数据,但是如果数据处理过程中全局变量数量较多,或者前后关联变量较多,每次调用python脚本时都需要频繁地读取变量,以及处理完了之后同样需要频繁地写入变量,并没有直接使用python脚本作为main程序方便,由于我们使用bash命令主要是cp文件,mkdir,以及grep关键词,所以通常情况下并不需要将这些命令写成脚本调用,而是希望在运行python程序过程中来调用某个命令,幸运的是,python提供这样的功能,以下简单介绍python的os模块。

二、python的os模块简介

os模块的简介参考python官方doc,以下作简单的翻译:


该模块提供了一种使用操作系统相关功能的可移植的方式。如果你只想要读写文件,参看open()函数,如果你想操作路径,参考os.path模块,如果你想在命令行上读取文件中的所有行,参考fileinput模块,要创建临时文件和目录,参考tempfile模块,对于更高级的文件和目录处理,请参考shutil模块。

关于这些功能可用性的说明:

  • python所有内置的依赖操作系统的模块的设计都是如此,即只要(操作系统)有相同的功能,它就使用相同的接口。例如,函数os.stat(path)以相同的格式返回有关path的统计信息(恰好都起源于POSIX接口)
  • 特定操作系统特有的扩展也可以通过os模块获得,但使用它们可能会降低程序的可移植性
  • 所有接受路径或文件名的函数都可以接受字节和字符串对象,如果函数返回路径或文件名,那么会生成与输入相同的类型
  • 在VxWorks上,不支持os.popen, os.fork, os.execv 和 os.spawnp
    注意:如果函数文件名和路径无效或不可访问,或其它类型正确但输入了操作系统不接受的参数,此模块中的所有函数都会抛出OSError(或其子类)
    doc

三、os.system和os.popen函数简介

os.system()函数

以下是python官网给的关于os.system函数的简介:
system


在子shell中执行命令(字符串),这是通过调用标准C语言的system()函数来实现的。对sys.stdin等的更改不会影响到执行命令的环境。如果命令生成任何输出,它将被发送到解释器标准输出流。标准C语言没有规定函数返回值的含义,因此python函数的返回值是和系统相关的。

在Unix上,返回值是以wait()函数指定的格式编码的进程的推出状态。在Windows上,返回值是系统shell运行命令后返回的值。

os.popen()函数

以下是官网给出的简介:
popen


打开一条与命令cmd之间的管道。返回值是一个连接到管道的打开的文件对象,根据传入的mode参数可以是"r"(默认)或"w"模式,缓冲区参数与python内置的open()函数具有相同的含义,返回的文件对象可以读取或写入字符串,但是不能是二进制类型。

如果子进程成功退出,close()方法返回None,如果有错误,则返回子进程的返回码。在POSIX系统上,如果返回值为正,则表示进程的返回值左移了一个字节,如果返回值为负,则进程被返回码的负值给出的信号终止。

四、实际使用

os.system()函数

使用该模块首先需要导入os模块,其使用相对简单,即将bash命令写成python字符串的形式,然后传入函数即可,以下是测试代码和结果:

1
2
3
4
5
import os
os.system("ls")
os.system("echo 'This is a test file!' > test.txt")
os.system("ls")
os.system("cat test.txt")

code1
可以看到使用方法很简单,相应bash命令的输出结果会输出到python的标准输出设备(屏幕)上,同时目录下也生成了相应的文件。

os.popen()函数

该模块会把bash命令的输出结果以可读的打开的文件的方式返回,便于后续继续使用,以下是测试代码和结果:

1
2
3
4
5
6
7
import os
file_path = "../OUTCAR"
cmd_get_energy = "grep 'energy without' {}|tail -1|awk '{{print $7}}'".format(file_path)
file_get_energy = os.popen(cmd_get_energy)
str_energy = file_get_energy.readline()
print(str_energy)
print(type(str_energy))

code2