专业的JAVA编程教程与资源

网站首页 > java教程 正文

使用python自动化脚本执行shell命令,提前两小时下班(5)

temp10 2024-12-25 15:46:33 java教程 15 ℃ 0 评论

今天我们来学习如何通过python脚本执行linux 操作系统命令,通过前面几期的学习,我们基本已经可以控制操作系统的目录和文件,切换到特定路径下,获取系统环境变量,获取用户命令行变量,跟用户进行入参交互。通过正则表达式过滤和加工我们需要的数据。

这次,我们来补遗,再次讲讲如何使用python脚本执行Linux shell脚本命令。

使用python自动化脚本执行shell命令,提前两小时下班(5)

有同学可能要问了,我直接写shell 不就完了,为啥需要多此一举用python调用shell呢?

python 的优势在哪里?

  1. python 编码调试更加容易,灵活性更高,变量有一定的类型。
  2. python 更加适合大规模,模块化的自动化脚本编写。

因此,目前工作中,涉及自动化脚本的场景,多用python替代shell。

于是,使用python执行shell命令,就是替换中的关键功能了,实际上前面有一期已经给大家介绍了四种python执行shell脚本命令的方式。

本次,我们聚焦于subprocess 这种官方推荐的形式,并给大家及进行详细介绍。

先看一个简单的示例:

import subprocess
>>> subprocess.run(["date"])
Fri Mar 22 21:16:26 CST 2024
// 通过python执行date shell命令,结果打印
CompletedProcess(args=['date'], returncode=0)
// 返回了一个CompletedProcess对象
// 可以看到返回值returncode 为0
// 代表正确执行返回

如果我们执行的语句出现错误会发生什么呢?

>>> result = subprocess.run(["ls", "file_not_exists"])
ls: cannot access 'file_not_exists': No such file or directory
>>> print(result.returncode)
2 // 我们发现,执行ls指令,失败后返回非0值

上面的一些shell命令,包括chmod, ls, date 等,我们一般只关心这些命令调用后是否成功,我们不需要对执行结果进行进一步处理时,直接判断执行返回值的returncode是否为0就足够了。

但是如果有一些shell命令,我们执行后,需要对执行结果进行进一步过滤,处理,获取一些有用信息时,那么上面的方式就不适用了。

那应该怎么办呢?

>>> result =
subprocess.run(["host", "8.8.8.8"], stdout=subprocess.PIPE)
>>> print(result.returncode)
0
>>> print(result.stdout)
b'8.8.8.8.in-addr.arpa domain name pointer dns.google.\n'
// 我们可以使用stdout属性或者capture_out=True
// 然后通过result.stdout获取到执行结果

host可以根据入参的ip地址,进行域名获取功能。

这里有个小tips,大家知道那个stdout显示结果的字符串前面为啥有个b不?

其实这代表的是,这个字符串它不是一个python标准的字符串,而是字节数组类型。

如果想进一步获取到python标准的字符串,可以使用decode方法。

>>> ret_list = result.stdout.decode().split()
// decode 之后split,存储为列表
>>> print(ret_list)
['8.8.8.8.in-addr.arpa', 'domain', 'name', 'pointer', 'dns.google.']
// 打印结果

那么如果我们执行某个shell指令错误,如何获取错误结果呢?答案是使用stderr。

示例如下:

>>> result = subprocess
 .run(["rm", "does_not_exists"],
 stderr=subprocess.PIPE, stdout=subprocess.PIPE)
// 想删除一个不存在的文件
>>> print(result.returncode)
1
>>> print(result.stdout)
b'' 
// 执行结果为空,因为出现错误了
>>> print(result.stderr)
b"rm: cannot remove 'does_not_exists': No such file or directory\n"
// 打印错误结果在stderr中

然后我们在学会了上面的基础使用方法后,考虑一种场景。

场景示例:

  1. 我们想执行一个自己的二进制程序,需要把这个程序的可执行文件路径添加到操作系统的环境变量中去。

如何实现这个功能呢?

示例如下:

>>> import os
>>> import subprocess
>>> my_env_to_run_app = os.environ.copy()
>>> my_env_to_run_app
= os.pathsep.join(["/opt/myapp/", 
my_env_to_run_app["PATH"]])
>>> result = subprocess.run(["myapp"], env = my_env_to_run_app)

我们通过os.environ.copy做环境变量的拷贝,然后添加自己的环境变量进去,然后在subprocess执行时,指定环境变量即可。

需要注意的是,subprocess 默认是启动了一个子线程去执行shell命令的,从上面的copy环境变量也可以看出,如果想执行一些命令直接作用在当前shell 中,则必须指定shell。

我们证明一下这件事情:

result = subprocess.run(["export", "Fruit=Apple"], shell=True)
// 导出一个环境变量Fruit
>>> print(result.returncode)
0 // 执行成功
>>> print(os.environ["LOGNAME"])
chen // 正常系统环境变量
>>> print(os.environ["Fruit"])
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.6/os.py", line 669, in __getitem__
    raise KeyError(key) from None
KeyError: 'Fruit'
// 发现通过subprocess export
// 的变量不在当前shell中,无法获取到

好的,今天就先讲到这里,你的关注就是我分享的动力,希望大家关注并给我留言,任何想听的想看的,都可以留言告诉我,给大家分享。

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表