【问题标题】:why is this linux command not working when executed using python?为什么这个 linux 命令在使用 python 执行时不起作用?
【发布时间】:2014-08-02 20:23:44
【问题描述】:

我想执行这个linux命令

"cat cflow_image.py | mailx -s "CFLOW Copy" foo@.foo.com"。我的要求是在python脚本中使用这个命令。我正在使用子进程模块来实现这个。

这是我的一段代码,

def send_mail(mailid): 
   # This is mail the testbed info to the user
   mailid = args.mailID 
   print "* INFO file will be sent to your mailid *"
   subprocess.call("cat info.txt | mailx -s \"DEVSETUP\" {0}").format(mailid)

以下是执行时的错误,

Traceback (most recent call last):
  File "dev-installer.py", line 243, in <module>
    send_mail(args.mailID)
  File "dev-installer.py", line 204, in send_mail
    subprocess.call("cat info.txt | mailx -s \"DEVSETUP\" {0}").format(mailid)
  File "/sw/packages/python/2.7.4/lib/python2.7/subprocess.py", line 524, in call
    return Popen(*popenargs, **kwargs).wait()
  File "/sw/packages/python/2.7.4/lib/python2.7/subprocess.py", line 711, in __init__
    errread, errwrite)
  File "/sw/packages/python/2.7.4/lib/python2.7/subprocess.py", line 1308, in _execute_child

【问题讨论】:

标签: python unix python-2.7 subprocess mailx


【解决方案1】:

你正在传递一个 shell 命令,所以 Python 应该调用一个 shell 来解析和运行你的命令。但是您是在告诉 Python 调用名称为 cat info.txt | mailx -s "DEVSETUP" foo@.foo.com 的命令,即在命令搜索路径上应该有一个使用该名称的可执行文件 - 并且不存在这样的命令。

subprocess.call 支持Popen 构造函数的所有关键字参数。您可以传递关键字参数shell=True 来表明您拥有的是一些shell 代码,而不是可执行文件的名称。

subprocess.call("cat info.txt | mailx -s \"DEVSETUP\" {0}".format(mailid),
                shell=True)

但是,请注意mailid 的值将被插入到 shell sn-p 中,如果它包含 shell 特殊字符,则会中断,如 bob@example.com (Bob Smith)Bob Smith &lt;bob@example.com&gt;。您应该安排引用 mailid 中存在的任何特殊字符。

您发布的命令的另一个问题是,如果在读取info.txt 时出现任何错误,将不会被检测到。您可以通过避免无用使用 cat 来解决这个问题:

subprocess.call("<info.txt mailx -s \"DEVSETUP\" {0}".format(mailid),
                shell=True)

鉴于命令很简单,您根本不需要调用 shell。如果没有 shell 参与,您无需担心引用。您可以轻松让 Python 打开info.txt 文件进行读取。

body_file = open("info.txt")
status = subprocess.call(["mailx", "-s", "DEVSETUP", mailid], stdin=body_file)
body_file.close()
if status != 0:
    … handle mailx failure …

【讨论】:

    【解决方案2】:

    subprocess.call 执行一个可执行文件。您没有将可执行文件的路径作为参数传递,而是传递了 shell 命令行。

    要执行 shell 命令,您必须通过在参数列表中传递 shell=True 来明确声明要在 shell 中执行命令。 请注意,将shell=True 与用户提供的命令一起使用可能存在安全隐患。

    还请注意,当您使用shell=True 时(例如,当您没有指定它时),您应该传递一个字符串列表作为表示已解析的参数列表的参数。 例如:

    subprocess.call('ls -l')
    

    将尝试执行名为 ls -l 的命令,如果您在 PATH 中没有具有该名称的可执行文件,则可能会失败,同时:

    subprocess.call(['ls', '-l'])
    

    将使用参数-l 调用ls 可执行文件。

    如果您不想手动编写此类列表,请使用shlex.split 解析“命令行”:

    subprocess.call(shlex.split('executable arg1 arg2 --option1 --option2 "string argument"'))
    

    会导致调用:

    subprocess.call(['executable', 'arg1', 'arg2', '--option1', '--option2', 'string argument'])
    

    注意引号是如何被正确处理的(但是没有执行 shell 扩展!)

    【讨论】:

    • 值得注意:如果外部用户可以以任何方式更改发给subprocess.call()的命令,请谨慎使用shell=True
    • @OozeMeister 这就是我所说的“将shell=True 与用户提供的命令一起使用可能会带来安全隐患。”
    猜你喜欢
    • 2014-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-15
    • 2016-10-09
    • 2021-10-17
    • 1970-01-01
    相关资源
    最近更新 更多