7

I'm trying to find a way to check the existence of a shell command before its execution.

For example, I'll execute the command ack-grep. So, I'm trying to do:

import subprocess
from subprocess import PIPE

cmd_grep = subprocess.Popen(["ack-grep", "--no-color", "--max-count=1", "--no-group", "def run_main", "../cgedit/"], stdout=PIPE, stderr=PIPE)

Than, if I execute

cmd_grep.stderr.read()

I receive '' like the output. But I don't have the command ack-grep on my path. So, why Popen is not putting the error message on my .stderr variable?

Also, is there a easyer way to do what I'm trying to do?

3
  • 3
    You should probably ask this on stackoverflow
    – trolle3000
    Jun 4, 2010 at 16:01
  • The best way to solve this, in my opinion, is to run command -v foo in a shell and check for an error status. Since that's a shell tool and not a python-specific tool, I'd say asking in SuperUser is appropriate, and I'd vote to reopen (at this late date). I would add it as an answer, but I can't since the question is closed. Feb 20, 2023 at 23:48
  • This is a built-in feature, just use shutil.which docs.python.org/3/library/shutil.html#shutil.which
    – Jonathan
    Mar 24, 2023 at 5:38

5 Answers 5

5

You can use the subprocess module under Python 3 or the commands module for Python 2 as follow :

status, result = subprocess.getstatusoutput("ls -al")

status, result = commands.getstatusoutput("ls -al")

Then test the value of status.

Examples from the website :

>>> import subprocess
>>> subprocess.getstatusoutput('ls /bin/ls')
(0, '/bin/ls')
>>> subprocess.getstatusoutput('cat /bin/junk')
(256, 'cat: /bin/junk: No such file or directory')
>>> subprocess.getstatusoutput('/bin/junk')
(256, 'sh: /bin/junk: not found')
2

couldn't you use the "which" command somehow? the which command automatically performs a lookup for an application in the paths. I think you would merely need to call this command and pass the name of the command you want to look up, then parse the results.

1

This should work out for you:

import subprocess 
from subprocess import PIPE
import shutil 

cmd = ["ack-grep", "--no-color", "--max-count=1", "--no-group", "def run_main", "../cgedit/"]
path_to_cmd = shutil.which(cmd[0])    
if path_to_cmd is None:
     print(f"There is no {cmd[0]} on the path!")
else:
    cmd_grep = subprocess.Popen(cmd,  stdout=PIPE, stderr=PIPE) 

The thought process......... I used this solution to start:

import subprocess
status, response = subprocess.getstatusoutput('which ack-grep')
print(f'Exitcode: {status}, Output: {response}')

But this resulted in a specific response only from Linux systems.

import shutil
shutil.which(cmd[0])

Returns the path to an executable when "ack-grep" is called or None if nothing is called.

1
  • This would be a better answer if you (1) used a more plausible (useful) example of commands, like the OP’s example of ack-grep versus grep, and (2) showed the code for using the command you want to use versus using the fallback. Jul 27, 2018 at 3:23
0

I finally left it working this way:

try:

    cmd_grep = ["ack-grep", "--no-color", "--max-count=1", "--no-group", function_definition, file_path]

    first_exec = Popen(cmd_grep,stdout=PIPE)

    execution = Popen(cmd_sed, shell=True, stdin=first_exec.stdout, stdout=PIPE)

except:

    #use grep instead

    cmd_grep = cmd_grep = r'grep -R -n "' + function_definition + '" ' + file_path

    execution = Popen(cmd_grep + '|' + cmd_sed,shell=True,stdout=PIPE)

output = execution.stdout.read()
0

For situations like this, I use:

def find_program(prog_filename, error_on_missing=False):
    bdirs = ['$HOME/Environment/local/bin/',
             '$HOME/bin/',
             '/share/apps/bin/',
             '/usr/local/bin/',
             '/usr/bin/']
    paths_tried = []
    for d in bdirs:
        p = os.path.expandvars(os.path.join(d, prog_filename))
        paths_tried.append(p)
        if os.path.exists(p):
            return p
    if error_on_missing:
        raise Exception("*** ERROR: '%s' not found on:\n  %s\n" % (prog_filename, "\n  ".join(paths_tried)))
    else:
        return None

Then you can do something like:

grep_path = find_program('ack_grep', False)
if grep_path is None:
    # default to standard system grep
    grep_path = 'grep'
1
  • This is not cross platform. And bdirs doesn't take into account the system $PATH env var
    – Jonathan
    Mar 24, 2023 at 5:35

Not the answer you're looking for? Browse other questions tagged .