Home > Enterprise >  Python subprocess.run() only runs commands up to first newline
Python subprocess.run() only runs commands up to first newline

Time:08-08

I'm looking into a bug on some software I use and I'm seeing unexpected behavior from python's subprocess.run(). When a command string is provided, it seems to only run the command up until the first newline (on windows). For example:

Example 1 - No newline:

python -c "import subprocess; from subprocess import PIPE; call = subprocess.run('''echo out 1 && echo out 2''', check=True, stdout=PIPE,stderr=subprocess.PIPE,shell=True,); print(call.stdout.decode('utf-8'))"

Output:

out 1
out 2

Example 2 - Same script except 1 newline in the command string:

python -c "import subprocess; from subprocess import PIPE; call = subprocess.run('''echo out 1
 && echo out 2''', check=True, stdout=PIPE,stderr=subprocess.PIPE,shell=True,); print(call.stdout.decode('utf-8'))"

Output:

out  1

I thought it might be an issue with reading the output, but I tried writing to a file before and after the newline, and it only worked before, so I think indeed the problem is that it only executes commands up to the newline.

How do I fully execute strings with newlines in them?

UPDATE:

Technically, I think below is the case that I need to work. The above case has && between the two echoes. The case below does not, as if they were two lines of an executing script:

python -c "import subprocess; from subprocess import PIPE; call = subprocess.run('''echo out 1
 echo out 2''', check=True, stdout=PIPE,stderr=subprocess.PIPE,shell=True,); print(call.stdout.decode('utf-8'))"

On Windows this prints 1 line, but on Ubuntu it prints 2.

CodePudding user response:

I discovered if you set subprocess to use pwsh instead of cmd it fixes the problem:

Set the environment variable COMSPEC to pwsh instead of cmd. For example in powershell:

$oldComSpec = $env:COMSPEC
try {
   $env:COMSPEC="$(Get-Command pwsh | select -ExpandProperty Source) -NoProfile"
   someScript.ps1
} finally {
   $env:COMSPEC = $oldComSpec

}

So far this is working for me.

CodePudding user response:

I'm not exactly sure why the rules of triple quotes didn't work here, but capping that broken string with the appropriate quotes seems to have fixed the issue. Maybe python -c doesn't handle triple quotes inside the string being passed because the string itself is considered in the same way triple quotes are? just my guess, hope this helps.

python -c "import subprocess; from subprocess import PIPE; call = subprocess.run('echo out 1'
'&& echo out 2', check=True, stdout=PIPE,stderr=subprocess.PIPE,shell=True,); print(call.stdout.decode('utf-8'))"
  • Related