[Tutor] run local script on a remote machine
Wolfgang Maier
wolfgang.maier at biologie.uni-freiburg.de
Thu Oct 27 03:57:55 EDT 2016
On 26.10.2016 19:44, Alex Kleider wrote:
>
> I've got three files as follows:
>
keeping just the relevant lines
...
> 2:
> #!/bin/bash
> #
> # file: call.sh
>
> # Demonstrates running a local python script on another host
> # with command line arguments specified locally.
>
> ssh -p22 alex at 10.10.10.10 python3 -u - one two three <
> /home/alex/Py/BackUp/Sandbox/Scripted/experiment.py
>
> 3:
> #!/usr/bin/env python3
> #
> # file: call.py
>
> import os
> import shlex
> import subprocess
>
> script = "/home/alex/Py/BackUp/Sandbox/Scripted/experiment.py"
> if os.path.isfile(script):
> print("File exists on local machine.")
> else:
> print("No such file.")
>
> command = (
> "ssh -p22 alex at 10.10.10.10 python3 -u - one two three < {}"
> .format(script))
>
> ret = subprocess.call(shlex.split(command))
>
...
>
> Running the shell script (2) executes a single shell command and leaves
> the junk.txt file at 10.10.10.10 as desired.
> Calling the same shell command using the subprocess module from with in
> a python script (3) does not work:
> alex at X301n3:~/Py/BackUp/Sandbox/Scripted$ ./call.py
> File exists on local machine.
> bash: /home/alex/Py/BackUp/Sandbox/Scripted/experiment.py: No such file
> or directory
The structure of the command you are trying to execute would require you
to set the "shell" argument of subprocess.call to True. Specifically,
the "<" redirection operator is shell functionality.
Quoting from
https://docs.python.org/3/library/subprocess.html?highlight=subprocess#subprocess.Popen:
"""
The shell argument (which defaults to False) specifies whether to use
the shell as the program to execute. If shell is True, it is recommended
to pass args as a string rather than as a sequence.
On POSIX with shell=True, the shell defaults to /bin/sh. If args is a
string, the string specifies the command to execute through the shell.
This means that the string must be formatted exactly as it would be when
typed at the shell prompt. This includes, for example, quoting or
backslash escaping filenames with spaces in them. If args is a sequence,
the first item specifies the command string, and any additional items
will be treated as additional arguments to the shell itself. That is to
say, Popen does the equivalent of:
Popen(['/bin/sh', '-c', args[0], args[1], ...])
"""
This is exactly the behaviour you are expecting from your code: the
shell gets called and sees a command for which the stdin should be
replaced with the contents of a local file; it does that and executes
the ssh command.
With the default shell=False, OTOH, the first item in your shlex.split
generated list, 'ssh', becomes the executable and gets called with the
rest of the list as arguments. ssh, however, does not interpret the '<'
sign like the shell, runs the remote shell command, the remote shell
sees and interprets the '<', fails to find the file on the remote
machine and errors out.
The simple solution should be to not split your command string, but pass
it directly to subprocess.call (untested):
subprocess.call(command, shell=True)
as long as you promise to NEVER use that code in production with user
input. The problem with it is that it may allow users to inject shell
commands as they like exactly because whatever ends up in the command
string gets interpreted by the shell.
Best,
Wolfgang
More information about the Tutor
mailing list