Python Popen does not work in compound command (PowerShell)

I am trying to use Python Popen to change my working directory and execute a command.

pg = subprocess.Popen("cd c:/mydirectory ; ./runExecutable.exe --help", stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True)
buff,buffErr = pg.communicate()

      

However, powershell returns "The system cannot find the path specified." There is a way...

If I run

 pg = subprocess.Popen("cd c:/mydirectory ;", stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True)

      

it returns the same.

However, if I run this: (no semicolon)

pg = subprocess.Popen("cd c:/mydirectory",stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True)

      

The command returns without errors. This leads me to believe that the semicolon is the problem. What is the reason for this behavior and how can I get around it?

I know I can just do c: /mydirectory/runExecutable.exe --help, but I would like to know why this is happening.

UPDATE:

I have tested passing the path to powershell as an argument for the Popen parameter executable

. It just powershell.exe

might not be enough. To find the true absolute path powershell

, execute where.exe powershell

. Then you can transfer it to Popen. Please note that shell

is still true. It will use the default shell, but pass the commandpowershell.exe

powershell = C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
pg = subprocess.Popen("cd c:/mydirectory ; ./runExecutable.exe", stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True, executable=powershell)
buff,buffErr = pg.communicate()
//It works!

      

+3


source to share


2 answers


In your call subprocess.Popen()

shell=True

means to use the platform default wrapper.

While the Windows world is - commendable - the move from CMD ( cmd.exe

) to PowerShell, Python determines which shell to invoke based on an environment variableCOMSPEC

that still points tocmd.exe

, even in the latest W10 update, which moved to PowerShell in terms of what the graphical user offers as the default shell.

For backward compatibility, this will not change anytime soon, and may never change.

Therefore your options are :

  • Use the syntax cmd

    as mentioned in the answer by Maurice Meyer .

  • Don't use shell = True

    and explicitly callpowershell.exe

    - see below.

  • Windows only: override environment variable COMSPEC

    before use shell = True

    - see below.


A simple Python example to invoke a binary file directly powershell

using command line commands, followed by a single line containing the PowerShell source code to execute:



import subprocess

args = 'powershell', '-noprofile', '-command', 'set-location /; $pwd'
subprocess.Popen(args)

      

Note that I deliberately used powershell

instead powershell.exe

because it opens up the possibility of a command running on Unix platforms after PowerShell Core .


Windows only: example c shell = True

, after overriding the environment variable, COMSPEC

first tell PowerShell:

import os, subprocess    

os.environ["COMSPEC"] = 'powershell'

subprocess.Popen('Set-Location /; $pwd', shell=True)

      

Note:

  • COMSPEC

    handled only on Windows; on Unix platforms, the shell executable is unchanged/bin/sh

  • Starting with Windows PowerShell v5.1 / PowerShell Core v6-beta.3, calling powershell

    with only -c

    (interpreted as -Command

    ) still loads the default profile files, which might have unexpected (with the explicit call powershell

    used above -noprofile

    suppresses this).

    • Changing the default behavior to not load profiles is the subject of this GitHub issue to align the PowerShell CLI with that of POSIX-like shells.
+4


source


You can execute multiple commands using the '&' character instead of a semicolon. Try the following:



pg = subprocess.Popen("cd c:/mydirectory & ./runExecutable.exe --help", stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True)
buff,buffErr = pg.communicate()

      

0


source







All Articles