Search code examples
pythonlinuxshellstdinio-redirection

Reading input for ssh from a file, using subprocess.Popen()


I am attempting to call a handful of local bash scripts that I have written for health checking applications on remote servers.

ssh -q <servername> "bash -s" -- < ./path/to/local/script.bash

The above runs perfectly fine from the command line. However, when I wrap the call in python, I keep getting errors stating:

bash: /path/to/file/script.bash: No such file or directory

As for my python, I am using the subprocess module. Python:

bashcmd="ssh -q %s \"bash -s\" -- < ./%s" % (<server>,<bashfilepath>)
process=subprocess.Popen(bashcmd.split, stdout=subprocess.PIPE)
output, error = process.communicate()

Any help would be appreciated!


Solution

  • Redirection in your first example is done by shell. Standard input for ssh read from the file ./path/to/local/script.bash, which ssh passes to the process on remote machine.

    You can not use shell redirections, because you are not running a command from shell. Instead you can use stdin and stdout arguments for Popen() to set the standard input and output for your process. You need to open the file and then pass the handle to stdin. This is explained in: Using files as stdin and stdout for subprocess.

    In python example, you pass ssh -q <server> "bash -s" -- < ./<filepath> as 1st argument to subprocess.Popen(), which excepts a list of arguments, or a single string: the path to the executable. You get No such file or directory error because your string argument is not a path to an executable. Correct format following the standard convention would be subprocess.Popen(["/path/to/executable", "arg1", "arg2", ...]).

    All this put together, your example should look something like:

    with open("./path/to/local/script.bash") as process_stdin:
        p = subprocess.Popen(["/usr/bin/ssh", "-q", server, "--", "bash", "-s"],
                             stdin=process_stdin, stdout=subprocess.PIPE)
        out, err = p.communicate()
    

    This all is explained in Python documentation for subprocess module.