Using back-ticks in a Python subprocess

I want to run this git command through a Python script and get its output:

git diff --name-only mybranch `git merge-base mybranch develop`

      

The team's goal is to see what changes have been made mybranch

since the last merge during development.

For this I use subprocess.Popen

:

output = subprocess.Popen(["git", "diff", "--name-only", "mybranch", "`git merge-base mybranch develop`"], stdout=subprocess.PIPE, shell=True)

      

However, this doesn't work. The variable output.communicate()[0]

just gives me a printout of git usage - essentially telling me that the input command is wrong.

I saw a similar question exists here , but it only told me to use shell=True

, which didn't solve my problem.

I also tried running two commands in a row, but that gave me the same result as before. It is possible that I missed something at this stage.

Any help or advice is greatly appreciated.

+3


source to share


2 answers


Backticks and subprocess

Return is a shell , you may have no choice but to use shell=True

, however pass the command line string , not the argument list

So, for your specific command (assuming it works in the first place)

process = subprocess.Popen("git diff --name-only mybranch `git merge-base mybranch develop`", stdout=subprocess.PIPE, shell=True)

      

Please note that when called Popen()

you get a process, shouldn't be called output

IMO

Here's a simple example that works with backticks



>>> process = subprocess.Popen('echo `pwd`', stdout=subprocess.PIPE, shell=True)
>>> out, err = process.communicate()
>>> out
'/Users/bakkal\n'

      

Or you can use the syntax $ (cmd)

>>> process = subprocess.Popen('echo $(pwd)', stdout=subprocess.PIPE, shell=True)
>>> out, err = process.communicate()
>>> out
'/Users/bakkal\n'

      

Here's what did NOT work (for reverse steps)

>>> process = subprocess.Popen(['echo', '`pwd`'], stdout=subprocess.PIPE, shell=True)
>>> out, err = process.communicate()
>>> out
'\n'
>>> process = subprocess.Popen(['echo', '`pwd`'], stdout=subprocess.PIPE, shell=False)
>>> out, err = process.communicate()
>>> out
'`pwd`\n'

      

+2


source


In POSIX, the argument list is passed /bin/sh -c

, i.e. only the first argument is recognized as a shell command, i.e. the shell starts up git

without any arguments, so you see usage information. You must pass the command as a string if you want to use shell=True

. From the subprocess

docs
:

In POSIX shell=True

, the default shell is /bin/sh

. If args

is string, the string specifies the command to execute through the shell. This means that the string must be formatted exactly as it would be when typed on the command line. This includes, for example, quoting or backslashes skipping filenames with spaces in them. If args

is a sequence, the first element indicates the command line, and any additional elements will be treated as additional arguments to the shell itself. That is, it Popen

performs the equivalent:

Popen(['/bin/sh', '-c', args[0], args[1], ...])

      



In this case, you don't need to shell=True

.

#!/usr/bin/env python
from subprocess import check_output

merge_base_output = check_output('git merge-base mybranch develop'.split(), 
                                 universal_newlines=True).strip()
diff_output = check_output('git diff --name-only mybranch'.split() +
                           [merge_base_output])

      

+2


source







All Articles