如何在Python脚本中通过Subprocess调用带HTML参数的Perl脚本
解决Python subprocess传递带复杂格式的命令问题
问题场景
Python脚本中调用Perl脚本发送通知,需要在--message参数中包含带超链接的内容,但因引号嵌套问题,命令无法在shell中执行;直接修改引号会触发Python语法错误。原函数及问题命令如下:
原函数代码:
def NotifierFunc(Mail, Ticket_Num, Open_DtTime): cmd = "/home/path/MyPerlScript.pl --channel 'MyChannel' --userid 'itsme' --message 'Hello <at>"+Mail+"<at> : The ticket <a href='`echo 'http://snview/'"+Ticket_Num+">`echo "+Ticket_Num+"`</a> is not closed for more than 72 hours : Open since "+Open_DtTime+" IST. Please close asap.' " print(cmd) subprocess.Popen(cmd, shell= True, stdout=subprocess.PIPE)
打印出的错误命令(引号嵌套混乱导致shell解析失败):
/home/path/MyPerlScript.pl --channel 'MyChannel' --userid 'itsme' --message 'Hello <at>Abc@xyz.com<at> : The ticket <a href='`echo 'http://snview/'INC23548>`echo INC23548`</a> is not closed for more than 72 hours : Open since 4-APR-2024 12:30:40 IST. Please close asap.'
已知在Linux命令行用双引号包裹--message内容可正常执行,但在Python中无法直接实现该格式。
解决方案
方法1:使用三重引号+格式化字符串解决引号嵌套
利用Python的三重双引号定义命令字符串,内部可直接使用双引号包裹--message内容,同时用f-string替换变量,避免字符串拼接的混乱,还能简化原命令中不必要的echo调用:
def NotifierFunc(Mail, Ticket_Num, Open_DtTime): # 三重双引号允许内部直接使用双引号,f-string简化变量替换 cmd = f"""/home/path/MyPerlScript.pl --channel 'MyChannel' --userid 'itsme' --message "Hello <at>{Mail}<at> : The ticket <a href='http://snview/{Ticket_Num}'>{Ticket_Num}</a> is not closed for more than 72 hours : Open since {Open_DtTime} IST. Please close asap." """ print(cmd) subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE)
方法2:避免shell=True,用参数列表传递(更安全推荐)
直接将命令拆分为参数列表传递给subprocess.Popen,无需处理任何引号嵌套,还能避免shell注入风险,是官方推荐的方式:
def NotifierFunc(Mail, Ticket_Num, Open_DtTime): # 先构造完整的message内容 message_content = f"Hello <at>{Mail}<at> : The ticket <a href='http://snview/{Ticket_Num}'>{Ticket_Num}</a> is not closed for more than 72 hours : Open since {Open_DtTime} IST. Please close asap." # 将命令拆分为参数列表,每个参数独立成项 cmd_args = [ "/home/path/MyPerlScript.pl", "--channel", "MyChannel", "--userid", "itsme", "--message", message_content ] # 可选:模拟打印shell格式的命令用于调试 print(' '.join(f"'{arg}'" if ' ' in arg else arg for arg in cmd_args)) # 无需shell=True,直接传递参数列表 subprocess.Popen(cmd_args, stdout=subprocess.PIPE)
内容的提问来源于stack exchange,提问作者instinct246
相关产品推荐
相关产品推荐

