简体   繁体   中英

Converting an os.system() to subprocess.call()

I'm a little shaky on the syntax of subprocess.call command arguments when those arguments include combined strings of variables

I have 4 variables that are used in the single complete command-string that ran successfully using os.system:

  • userPWD
  • userName
  • hostName
  • path

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

Now converting that to subprocess.call which will give me the needed output status I need, the format of some aspects of this command-string is loosing me, as the subprocess.call documentation usually just shows very simple commands like this:

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

My first effort to convert it looks like this:

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

but this produces the following error messages in 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

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

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

In general, I don't think using shell=True in the subprocess families is a good idea. This is a very well-known vector of attack (or inconvenience). The malicious (or clueless) user may inject arbitrary shell command. In your case the password field seems to be in control of the user, so there could be a risk. The reason one refrains from using os.system is to prevent this kind of error.

Here, I presume you're using scp to pull files from the remote to the local host. In that case shell * globbing doesn't matter, because this is expanded by the remote shell.

Your stack trace says the problem is that the executable, in your case sshpass , cannot be located. This is likely because the directory containing the executable isn't in your PATH environment variable.

To correct this, you can simply modify PATH temporarily as you call the command, in the following fake Python (you need to fill in your own details):

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)

The code will first check if the directory of sshpass is in the PATH . If not, it is prefixed to the PATH and used for command execution.

Alternatively, just use the absolute path:

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

Finally, a word of caution: Just say no to sshpass . It's insecure, hence evil. Use public-key based SSH authentication by starting ssh-agent before executing automated commands. Dispense with passwords, especially passwords passed by sshpass -p . They're evil. Just Say No.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM