Arno
Arno

Reputation: 329

Correct use of subprocess.Popen to issue a command via SSH

Other posts touch on the topic but I'm still not clear as to why this works:

command = "echo /sbin/poweroff | ssh admin@" + address
shutcmd = subprocess.Popen(command, stdout = subprocess.PIPE, shell=True)

and this doesn't work:

 shutcmd = subprocess.Popen(["echo", "/sbin/poweroff" "|" "ssh", "admin@",address], stdout = subprocess.PIPE, stderr = subprocess.PIPE)

How would you do this correctly?

Upvotes: 2

Views: 3909

Answers (2)

James Mills
James Mills

Reputation: 19030

Because | is shell syntax and semantics.

You would simulate this by doing:

from subprocess import Popen, PIPE, STDOUT

user = "root"
host = "1.2.3.4"

p = Popen(
    ["ssh", "{}@{}".format(user, host)],
    stdin=PIPE, stdout=PIPE, stderr=STDOUT
)
stdout, stderr = p.communicate("/sbin/poweroff\n")

However it's even simpler to just issue the command itself as an argument to ssh:

p = Popen(
    ["ssh", "{}@{}".format(user, host), "/sbin/poweroff"],
)
p.wait()

As an aside; the reason your first example works at all is because of shell=True. A shell is involved to run your "piece of shell" so therefore the new shell that is spawned has it's own set of fd triples for stdin, stdout and stderr; so echo | ssh work.

See: Pipeline (UNIX)

Upvotes: 3

Eric Renouf
Eric Renouf

Reputation: 14490

You can just pass the command to run to ssh, you don't have to pipe into it.

Try

shutcmd = subprocess.Popen(['ssh', 'admin@' + address, '/sbin/poweroff'], stdout=subprocess.PIPE, stderr=subprocess.PIPE)

Upvotes: 1

Related Questions