From: Hans Mulder on
Chris Rebert wrote:

> `where` seems to be a zsh built-in:
> $ # I'm in UR bash
> $ nonexistent
> -bash: nonexistent: command not found
> $ where bash
> -bash: where: command not found
>
> And not everyone has zsh installed, so...
> I don't see why one shouldn't use the standard `which` *nix command instead.

Because `which` ia a C shell script. It reads your .cshrc, to see which
aliases would be defined if you were to use the C shell, but it doesn't
look at your .bashrc.

You're probably better off using `type`: it knows about built-ins and
shell functions and that sort of stuff:

$ which type
/usr/bin/type
$ type type
type is a shell builtin
$

Guess which answer is more relevant to you .....

HTH,

-- HansM
From: Kenny Meyer on
Chris Rebert (clp2(a)rebertia.com) wrote:
> On Mon, Jul 12, 2010 at 6:29 PM, Kenny Meyer <knny.myer(a)gmail.com> wrote:
> > Hello,
> >
> > I have to figure out if a string is callable on a Linux system. I'm
>
> "callable" seems vague. Is a command string with invalid arguments but
> a valid executable "callable"? If no, then there's no general way to
> test "callability" without actually running the command.

I'm glad you pointed that out, because you're right. I subconciously
meant a file that is in the $PATH.

[snip]
>
> Well, you're not gonna be able to get the command's return code
> without actually running it (unless perhaps you're referring to a
> return code from the shell itself?).
>
> > What are better ways of doing this?
>
> One idea:
>
> from shlex import split as shell_tokenize
> from subprocess import check_output
>
> def is_valid_command(command):
> try:
> executable = shell_tokenize(command)[0]
> except (ValueError, IndexError):# invalid shell syntax
> return False
> return bool(check_output(['which', executable]))# on the PATH?
>
I have tried this and found some unexpected issues with Python 2.6 which I
though I should point out:

Firstly, the function `check_output` in the `subprocess` module only comes with
Python 2.7, but I have found a similar function called `check_call` [1] which
seems is similar, but not the same.

[1] http://docs.python.org/library/subprocess.html#subprocess.check_call

The code now looks like this:

from shlex import split as shell_tokenize
from subprocess import check_call, CalledProcessError

def is_valid_command(command):
try:
executable = shell_tokenize(command)[0]
check_call(['which', executable]) # Raises CalledProcessError if
# something went wrong
return True
except (ValueError, IndexError, CalledProcessError): # Catch exception if there
# was an error calling the process
return False

The idea with `which` is really great one.

Thanks a lot, for your time and your input.

--
Onward and upwards,
Kenny Meyer
From: Kenny Meyer on
On Jul 13, 4:14 pm, Hans Mulder <han...(a)xs4all.nl> wrote:
> Chris Rebert wrote:
> > `where` seems to be a zsh built-in:
> > $ # I'm in UR bash
> > $ nonexistent
> > -bash: nonexistent: command not found
> > $ where bash
> > -bash: where: command not found
>
> > And not everyone has zsh installed, so...
> > I don't see why one shouldn't use the standard `which` *nix command instead.
>
> Because `which` ia a C shell script.  It reads your .cshrc, to see which
> aliases would be defined if you were to use the C shell, but it doesn't
> look at your .bashrc.
>
> You're probably better off using `type`: it knows about built-ins and
> shell functions and that sort of stuff:
>
> $ which type
> /usr/bin/type
> $ type type
> type is a shell builtin
> $
>
> Guess which answer is more relevant to you .....
>
> HTH,
>
> -- HansM

Oh thanks, Hans! `type` seems to a good alternative. Surely it can
also get the job (better) done.
From: Steven W. Orr on
On 07/12/10 21:29, quoth Kenny Meyer:
> Hello,
>
> I have to figure out if a string is callable on a Linux system. I'm
> actually doing this:
>
> def is_valid_command(command):
> retcode = 100 # initialize
> if command:
> retcode = subprocess.call(command, shell=True)
> if retcode is 0:
> print "Valid command."
> else:
> print "Looks not so good..."
>
> is_valid_command("ls")
>
> Never mind the code, because this is not the original.
> The side effect of subprocess.call() is that it *actually* executes
> it, but I just need the return code. What are better ways of doing
> this?

Luke! Use the force!

#! /usr/bin/python

import os
def is_valid_command(command):
looking_good = False
for ii in os.environ['PATH'].split(':'):
if os.access(ii + '/' + command, os.X_OK):
looking_good = True
break
print ["Looks not so good...", "Valid command."][looking_good]

is_valid_command('python')
is_valid_command('pythoon')

This way you don't start up any subprocesses and you are actually doing what
the shell would do for you.

THE ONLY DIFFERENCE is that a persistent bash would hash all of the contents
of what lives in PATH and so might have a slight shot of being faster under
somewhat obscure conditions.

I would strongly encourage you to not execute an arbitrary string to see if it
returns a pretty return code.

is_valid_command('{cd /; rm -rf /}')

Warning:
* It only checks if the command exists in PATH and is executable TO YOU:
* Do not make fun of is_valid_command. It will get angry.
* You might also want to beef it up a la
pp = ii + '/' + command
if os.access(pp, (os.X_OK) and not os.stat.isdir(p)):
so you are checking executable files and not directories etc...
* More warnings can be amplified upon over pitchers of beer.

--
Time flies like the wind. Fruit flies like a banana. Stranger things have .0.
happened but none stranger than this. Does your driver's license say Organ ..0
Donor?Black holes are where God divided by zero. Listen to me! We are all- 000
individuals! What if this weren't a hypothetical question?
steveo at syslang.net

From: Grant Edwards on
On 2010-07-14, Steven W. Orr <steveo(a)syslang.net> wrote:
> On 07/12/10 21:29, quoth Kenny Meyer:
>
>> I have to figure out if a string is callable on a Linux system. I'm
>> actually doing this:
>>
>> def is_valid_command(command):
>> retcode = 100 # initialize
>> if command:
>> retcode = subprocess.call(command, shell=True)
>> if retcode is 0:
>> print "Valid command."
>> else:
>> print "Looks not so good..."
>>
>> is_valid_command("ls")
>>
>> Never mind the code, because this is not the original. The side
>> effect of subprocess.call() is that it *actually* executes it, but I
>> just need the return code. What are better ways of doing this?
>
> Luke! Use the force!
>
> #! /usr/bin/python
>
> import os
> def is_valid_command(command):
> looking_good = False
> for ii in os.environ['PATH'].split(':'):
> if os.access(ii + '/' + command, os.X_OK):
> looking_good = True
> break
> print ["Looks not so good...", "Valid command."][looking_good]
>
> is_valid_command('python')
> is_valid_command('pythoon')

Just to be clear, that's not the same as the OP's code in two
respects:

1) It doesn't handle shell builtins or aliases.

2) It determines not whether a command is valid (returns 0), but
whether a command exists as an executable. "Valid" is a rather
small subset of "exists".

Of course the OP didn't explain what he meant by "callable", so all we
have to go on is his posted code.

> This way you don't start up any subprocesses and you are actually
> doing what the shell would do for you.
>
> THE ONLY DIFFERENCE is that a persistent bash would hash all of the
> contents of what lives in PATH and so might have a slight shot of
> being faster under somewhat obscure conditions.

No, there are other differences. See above.

> I would strongly encourage you to not execute an arbitrary string to
> see if it returns a pretty return code.
>
> is_valid_command('{cd /; rm -rf /}')
>
> Warning:

> * It only checks if the command exists in PATH and is executable TO
> YOU:

Which is different than determining whether a command (including
arguments) is valid (callable and returns 0). However, running a
command to determine if it's valid is going to cause problems sooner
or later due to side-effects of that command.

For example, the first time you the command "rm /path/to/a/file" it
may be valid, but the second time it won't be.

> * Do not make fun of is_valid_command. It will get angry.

And don't taunt happy fun ball!

> * You might also want to beef it up a la
> pp = ii + '/' + command
> if os.access(pp, (os.X_OK) and not os.stat.isdir(p)):
> so you are checking executable files and not directories etc...
> * More warnings can be amplified upon over pitchers of beer.


--
Grant Edwards grant.b.edwards Yow! My mind is making
at ashtrays in Dayton ...
gmail.com