0

I'm trying to write a function that will issue commands via ssh with Popen and return the output.

def remote(cmd):
    escaped = escape(cmd)
    return subprocess.Popen(escaped, ...).communicate()[0]

My trouble is how to implement the escape function. Is there a Python module (2.6) that has helpers for this? Google shows there's pipes.quote and re.escape but they seem like they only work for locally run commands. With commands passed to ssh, it seems the escaping needs to be more stringent:

For example on a local machine, this is ok:

echo $(hostname)

When passing to ssh it has to be:

ssh server "echo \$(hostname)"

Also, double quotes can be interpreted in different ways depending on the context. For literal quotes, you need the following:

ssh a4ipe511 "echo \\\"hello\\\""

To do variable exansion, double quotes are also used:

ssh a4ipe511 "echo \"\$(hostname)\""

As you can see, the rules for escaping a command that goes into SSH can get pretty complicated. Since this function will be called by anyone, I'm afraid some complex commands will cause the function to return incorrect output.

Is this something that can be solved with a built-in Python module or do I need to implement the escaping myself?

1 Answer 1

1

First:

pipes.quote and re.escape have nothing to do with locally run commands. They simply transform a string; what you do with it after that is your business. So either -- in particular pipes.quote -- is suitable for what you want.

Second:

If you want to run the command echo $(hostname) on a remote host using ssh, you don't need to worry about shell escaping, because subprocess.Popen does not pass your commands into a shell by default. So, for example, this works just fine:

>>> import subprocess
>>> subprocess.call([ 'ssh', 'localhost', 'echo $(hostname)'])
myhost.example.com
0

Double quotes also work as you would expect:

>>> subprocess.call([ 'ssh', 'localhost', 'echo "one   two"; echo three'])
one   two
three
0

It's not clear to me that you actually have a problem.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, your solution worked perfectly. It looks like passing as a sequence with shell=False did the trick, which solves the problem. Though I think this may still be an issue for anyone who wants to solve this problem by passing a string argument and using shell=True.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.