1

I would like to run a subprocess from Python. Inside the command string are several subcommands with backticks:

subprocess = subprocess.Popen(
    [
        "echo",
        "COMMAND [`date +%%s`] SCHEDULE_HOST_DOWNTIME;%s;`date +%%s`;`date -d 'now + %d sec' +%%s`;1;;;%s;Downtime comment" % (hostname, 300, username)
    ],
    stdout=subprocess.PIPE
)

Though the date commands in the back ticks are not executed. The stdout of this command is:

COMMAND [`date +%s`] SCHEDULE_HOST_DOWNTIME;example.com;`date +%s`;`date -d 'now + 300 sec' +%s`;1;;;my-username;Downtime comment

I also tried to use $(date +%s) instead of backticks and explicitly sent it to bash via subprocess.Popen(["/bin/bash", "-c", "echo", "..."], with the same result.

How can this be solved? I know I can of course use Pythons datetime module in this specific case. But I want to know why this is not working and how to solve it without tearing apart the command. While I'm here able to run the timestamp calculation easily in Python, in other cases it might be more complicated, where I would be forced to run several subprocesses which gets quickly very ugly.

buhtz
  • 10,774
  • 18
  • 76
  • 149
udondan
  • 57,263
  • 20
  • 190
  • 175
  • unrelated: you could call `int(time.time())` in Python to emulate `date +%s` shell command. – jfs Feb 02 '15 at 18:27

1 Answers1

10

Backticks are a shell syntax feature, but you are not running your command in a shell. The subprocess module runs the command directly.

Provide one string rather than a list, and set shell=True if the shell needs to process the command as one entry:

subprocess = subprocess.Popen(
    'echo "COMMAND [`date +%%s`] SCHEDULE_HOST_DOWNTIME;%s;`date +%%s`;`date -d \'now + %d sec\' +%%s`;1;;;%s;Downtime comment"' % (hostname, 300, username),
     stdout=subprocess.PIPE
     shell=True)
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • That was quick and correct. The echo string needs to be quoted but works perfect. Thanks! – udondan Feb 02 '15 at 11:06
  • @DanielSchroeder: added in the quoting for you. – Martijn Pieters Feb 02 '15 at 11:12
  • 1
    Alternately, capture the output of `date +%s` via `subprocess.Popen`, or directly using python's time functions & then formulate the string via string concatenation, if you want to avoid `shell=True`... (I've seen some people who don't like `shell=True`... :D ) – anishsane Feb 02 '15 at 11:46
  • 1
    @anishsane: as the OP stated, the example is contrived. But the 'not liking' part is rooted in security. If `hostname` or `username` is in any way influenced by an outside user, then an attacker could take over that shell for their own purposes. – Martijn Pieters Feb 02 '15 at 11:51