将os.system()转换为subprocess.call()

时间:2017-04-27 21:29:07

标签: python python-2.7 subprocess

当这些参数包含变量的组合字符串时,我对subprocess.call命令参数的语法有点不稳定

我有4个变量用于使用os.system成功运行的单个完整命令字符串:

  • userPWD
  • 的userName
  • 主机名
  • 路径

    os.system(“sshpass -p%s scp%s @%s:/var/tmp/*Metrics.csv%s”%(userPWD,userName,hostName,path))

现在将它转换为subprocess.call,它将为我提供所需的输出状态,这个命令字符串的某些方面的格式让我失望,因为subprocess.call文档通常只显示非常简单的命令,如下所示:

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

我转换它的第一个努力看起来像这样:

subprocess.call(["sshpass", "-p", userPWD, "scp", "userName@hostName:/var/tmp/*Metrics.csv", path"])

但是这会在Python 2.7.3中产生以下错误消息:

Traceback (most recent call last):
  File "pyprobeConnect.py", line 73, in <module>
    get_csvPassFail = subprocess.Popen("sshpass -p %s scp %s@%s:/var/tmp/*Metrics.csv %s" % (userPWD, userName, hostName, path)).read()
  File "/usr/lib/python2.7/subprocess.py", line 679, in __init__
    errread, errwrite)
  File "/usr/lib/python2.7/subprocess.py", line 1249, in _execute_child
    raise child_exception
OSError: [Errno 2] No such file or directory

2 个答案:

答案 0 :(得分:0)

当您包含*时,您需要传递shell=True,如果您传递shell=True,则需要将第一个参数指定为字符串而不是列表。

subprocess.call("sshpass -p %s scp %s@%s:/var/tmp/*Metrics.csv %s" % (userPWD, userName, hostName, path),shell=True)

答案 1 :(得分:0)

一般情况下,我不认为在shell=True家庭使用subprocess是一个好主意。这是一个非常着名的攻击传播(或不便)。恶意(或无能)用户可能注入任意shell命令。在您的情况下,密码字段似乎在用户的控制之下,因此可能存在风险。一个人不使用os.system的原因是为了防止出现这种错误。

在此,我假设您正在使用scp将文件从远程数据库提取到本地主机。在这种情况下,shell * globbing并不重要,因为它是由远程shell扩展的。

您的堆栈跟踪说明问题在于无法找到您的案例sshpass中的可执行文件。这可能是因为包含可执行文件的目录不在您的PATH环境变量中。

要解决此问题,您可以在调用命令时暂时修改PATH,在以下假Python中(您需要填写自己的详细信息):

import os
cur_path = os.environ["PATH"]
if dir_of_your_executable not in cur_path:
    cmd_path = "%s:%s" % (dir_of_your_executable, cur_path)
else:
    cmd_path = cur_path
cmd_env = os.environ.copy().update(PATH=cmd_path)
subprocess.call(["sshpass", "rest", "of", "your", "command"], env=cmd_env)

代码首先会检查sshpass的目录是否在PATH中。如果没有,则它以PATH为前缀,用于执行命令。

或者,只需使用绝对路径:

subprocess.call(["/path/to/sshpass", "rest", "of", "your", "command"])

最后,请注意:只对sshpass说不。它不安全,因此是邪恶的。在执行自动命令之前,通过启动ssh-agent来使用基于公钥的SSH身份验证。使用密码进行分配,尤其是sshpass -p传递的密码。他们是邪恶的。只是说不。