Python的subprocess模块是用于创建和管理子进程的模块。它提供了一种在Python中调用外部命令的方式,可以执行系统命令、启动新的进程、连接到子进程的输入/输出管道等。
subprocess.run(args, *, stdin=None, input=None, stdout=None,
stderr=None, capture_output=False, text=None,
check=False, timeout=None, encoding=None, errors=None)
import subprocess
def execute_update_ip_sh(ip):
"""
执行修改配置文件 ip 脚本,将会修改ky_ai_solution.json、nginx.conf、vsftpd.conf 等文件中的ip
"""
try:
# 构建命令
command = ['/ky/update_ip.sh', ip]
# 执行命令并获取输出(这个出错直接就抛异常了,不能捕获标准输出和标准错误)
# result = subprocess.check_output(command, universal_newlines=True)
result = subprocess.run(command, stdout=subprocess.PIPE,
stderr=subprocess.PIPE, universal_newlines=True)
# 打印脚本的输出
print(f"[{command}] 标准输出:", result.stdout)
# 打印脚本的错误输出(打印不出来)
print(f"[{command}] 标准错误输出:", result.stderr)
# 执行成功,返回True
return result.returncode == 0
# except subprocess.CalledProcessError as e:
except Exception as e:
# 执行失败,返回False
print(e)
print("ddddddddddddddddddddddddddddddddddddddd")
return False
if __name__ == "__main__":
execute_update_ip_sh("192.168.1.140")
subprocess.Popen(args, bufsize=-1, executable=None,
stdin=None, stdout=None, stderr=None,
preexec_fn=None, close_fds=True,
shell=False, cwd=None, env=None,
universal_newlines=False, startupinfo=None,
creationflags=0, restore_signals=True,
start_new_session=False, pass_fds=(), *,
encoding=None, errors=None)
args
:要执行的命令及其参数。可以是一个字符串或一个字符串列表。bufsize
:指定缓冲区的大小。默认值为-1,表示使用系统默认的缓冲区大小。executable
:指定要执行的可执行文件的路径。默认值为None,表示使用系统默认的可执行文件。stdin
:指定子进程的标准输入。可以是一个文件对象或一个文件描述符。默认值为None,表示使用父进程的标准输入。stdout
:指定子进程的标准输出。可以是一个文件对象或一个文件描述符。默认值为None,表示使用父进程的标准输出。stderr
:指定子进程的标准错误输出。可以是一个文件对象或一个文件描述符。默认值为None,表示使用父进程的标准错误输出。preexec_fn
:在子进程执行前调用的可调用对象。默认值为None,表示不调用任何函数。当使用shell=True
时,subprocess.Popen()
函数创建的子进程实际上是一个shell进程,而不是直接执行的命令。因此,向Popen
对象发送信号并不能直接影响到子进程。
如果需要向通过shell执行的命令发送信号,可以使用os.killpg()
函数来发送信号给进程组。具体步骤如下:
Popen
对象时,设置preexec_fn=os.setsid
,以创建一个新的进程组。os.killpg()
函数发送信号给进程组。下面是一个示例,演示了如何向通过shell执行的命令发送信号:
import subprocess
import os
import signal
# 通过shell执行命令
process = subprocess.Popen('sleep 10', shell=True, preexec_fn=os.setsid)
# 发送信号给进程组
os.killpg(os.getpgid(process.pid), signal.SIGTERM)
在这个示例中,首先通过subprocess.Popen()
函数创建了一个通过shell执行的命令。在创建Popen
对象时,通过preexec_fn=os.setsid
设置了preexec_fn
参数,以创建一个新的进程组。
然后,使用os.killpg()
函数发送信号给进程组。在这个示例中,发送了SIGTERM
信号,即终止信号。
需要注意的是,向进程组发送信号会影响到进程组中的所有进程。因此,如果有多个通过shell执行的命令,它们都属于同一个进程组,发送信号时需要注意。
close_fds
:指定是否在子进程中关闭父进程中打开的文件描述符。默认值为True,表示关闭文件描述符。shell
:指定是否通过shell来执行命令。默认值为False,表示不通过shell执行命令。当shell
参数设置为True
时,表示通过shell来执行命令。这意味着可以使用shell的语法和功能,比如管道、重定向、通配符等。在这种情况下,args
参数可以是一个字符串,表示要执行的完整命令。
当shell
参数设置为False
时,表示不通过shell来执行命令。这是默认的行为。在这种情况下,args
参数应该是一个字符串列表,其中第一个元素是要执行的命令,后续元素是命令的参数。
需要注意的是,使用shell=True
时,应该谨慎处理输入参数,避免命令注入等安全问题。应该始终对用户输入进行验证和过滤,避免直接将用户输入拼接到命令中。
下面是一个示例,演示了shell
参数的用法:
import subprocess
# 通过shell执行命令
subprocess.Popen('ls -l', shell=True)
# 不通过shell执行命令
subprocess.Popen(['ls', '-l'])
在这个示例中,第一个Popen()
函数调用通过shell执行了ls -l
命令,而第二个Popen()
函数调用不通过shell执行了ls -l
命令。
下面是一个示例,演示了如何通过shell执行命令并使用管道:
import subprocess
# 通过shell执行命令并使用管道
process = subprocess.Popen('ls -l | grep .txt', shell=True)
# 等待子进程结束
process.wait()
在这个示例中,通过subprocess.Popen()
函数的shell
参数设置为True
,表示通过shell执行命令。然后,可以使用shell的管道语法|
将两个命令连接起来,实现输出过滤。
import subprocess
# 不通过shell执行命令并使用管道
command1 = subprocess.Popen(['ls', '-l'], stdout=subprocess.PIPE)
command2 = subprocess.Popen(['grep', '.txt'], stdin=command1.stdout, stdout=subprocess.PIPE)
# 获取命令2的输出
output = command2.communicate()[0]
# 打印输出结果
print(output.decode())
在这个示例中,首先创建了两个Popen()
对象,分别对应两个命令。command1
执行了ls -l
命令,并将输出通过管道传递给command2
。command2
执行了grep .txt
命令,并将结果输出到标准输出。
通过command2.communicate()
方法获取命令2的输出,并将其打印出来。
不通过shell执行命令时,需要手动设置命令之间的输入输出关系,以及处理命令的输出。这需要更多的代码来实现,但也提供了更多的灵活性和控制能力。
cwd
:指定子进程的当前工作目录。默认值为None,表示使用父进程的当前工作目录。env
:指定子进程的环境变量。可以是一个字典,表示环境变量的键值对。默认值为None,表示使用父进程的环境变量。universal_newlines
:指定是否将输入/输出流以文本模式打开。默认值为False,表示以二进制模式打开。startupinfo
:指定子进程的启动信息。可以是一个subprocess.STARTUPINFO对象,用于设置子进程的一些属性。默认值为None。creationflags
:指定子进程的创建标志。默认值为0,表示使用默认的创建标志。restore_signals
:指定是否在子进程中恢复信号处理程序。默认值为True,表示恢复信号处理程序。start_new_session
:指定是否在新的会话中启动子进程。默认值为False,表示在当前会话中启动子进程。pass_fds
:指定要传递给子进程的文件描述符列表。默认值为(),表示不传递文件描述符。encoding
:指定输入/输出的编码方式。默认值为None,表示使用系统默认的编码方式。errors
:指定输入/输出的错误处理方式。默认值为None,表示使用系统默认的错误处理方式。subprocess.Popen()
函数会返回一个Popen对象,可以用于与子进程进行交互。Popen对象具有一些常用的方法和属性,比如communicate()
、wait()
、poll()
、terminate()
、kill()
、stdout
、stderr
和returncode
等。
下面是一个使用subprocess模块的示例,演示了如何执行一个系统命令并获取其输出:
import subprocess
# 执行系统命令
result = subprocess.run(['ls', '-l'], capture_output=True, text=True)
# 获取命令的输出
output = result.stdout
print(output)
以上代码会执行ls -l
命令,并将其输出打印出来。
需要注意的是,subprocess模块在执行外部命令时,存在一定的安全风险,特别是在使用shell=True参数时。因此,在使用subprocess模块时,应该谨慎处理输入参数,避免命令注入等安全问题。
subprocess.check_output
函数是Python标准库subprocess
模块中的一个函数,用于执行系统命令并返回命令的输出结果。
它的用法是:
subprocess.check_output(args, *, stdin=None, stderr=None,
shell=False, universal_newlines=False)
其中,args
是一个字符串或者字符串列表,表示要执行的命令及其参数。stdin
、stderr
、shell
和universal_newlines
是可选参数,用于控制输入、错误输出、是否使用shell以及输出结果的编码方式。
check_output
函数会执行指定的命令,并等待命令执行完成。如果命令执行成功,它会返回命令的输出结果(以字节字符串的形式),如果命令执行失败,它会抛出一个CalledProcessError
异常。
在上述代码中,subprocess.check_output
函数被用于执行一些系统命令,如ip addr show
和ip route show
,以获取当前以太网接口的IP配置信息。