Check if a command is valid

Discussion in 'Python' started by Kenny Meyer, Jul 13, 2010.

  1. Kenny Meyer

    Kenny Meyer Guest

    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?
    Kenny Meyer, Jul 13, 2010
    #1
    1. Advertising

  2. Kenny Meyer

    Chris Rebert Guest

    On Mon, Jul 12, 2010 at 6:29 PM, Kenny Meyer <> 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.

    > actually doing this:
    >
    >    def is_valid_command(command):
    >        retcode = 100 # initialize
    >        if command:
    >            retcode = subprocess.call(command, shell=True)
    >        if retcode is 0:


    That should be `== 0`, not `is 0`. The fact that `is 0` just so
    happens to work is an implementation detail.

    >            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.


    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?

    Cheers,
    Chris
    --
    http://blog.rebertia.com
    Chris Rebert, Jul 13, 2010
    #2
    1. Advertising

  3. Kenny Meyer wrote:
    > 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?
    >

    I'm not sure I get exactly what you're searching for but here's
    something that may help.

    If you just whant to know if a command (without parameter) is a Linux
    command (either a builtin, alias of file exe) you can use the "where"
    command and inspect its return code, the command is not executed though.

    >where ls

    ls is an alias for ls --color=auto -F
    ls is /bin/ls
    >where apt-get

    apt-get is /usr/bin/apt-get
    >where doesnotexists

    doesnotexists not found
    zsh: exit 1

    retcode = subprocess.call(command, shell=True)

    becomes

    retcode = subprocess.call("where " + command)

    JM

    NB : this does not work with parameters appened to the command.
    Jean-Michel Pichavant, Jul 13, 2010
    #3
  4. Kenny Meyer

    Chris Rebert Guest

    On Tue, Jul 13, 2010 at 4:33 AM, Jean-Michel Pichavant
    <> wrote:
    > Kenny Meyer wrote:
    >> 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?
    >>

    >
    > I'm not sure I get exactly what you're searching for but here's something
    > that may help.
    >
    > If you just whant to know if a command (without parameter) is a Linux
    > command (either a builtin, alias of file exe) you can use the "where"
    > command and inspect its return code, the command is not executed though.
    >
    >>where ls

    > ls is an alias for ls --color=auto -F
    > ls is /bin/ls
    >>where apt-get

    > apt-get is /usr/bin/apt-get
    >>where doesnotexists

    > doesnotexists not found
    > zsh: exit 1


    `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..

    Also, in retrospect, my suggestion should probably have checked the
    return code rather than the output; more efficient and simple that
    way.

    Cheers,
    Chris
    --
    http://blog.rebertia.com
    Chris Rebert, Jul 13, 2010
    #4
  5. Kenny Meyer

    Hans Mulder Guest

    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
    Hans Mulder, Jul 13, 2010
    #5
  6. Kenny Meyer

    Kenny Meyer Guest

    Chris Rebert () wrote:
    > On Mon, Jul 12, 2010 at 6:29 PM, Kenny Meyer <> 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

    -----BEGIN PGP SIGNATURE-----
    Version: GnuPG v1.4.10 (GNU/Linux)

    iEYEARECAAYFAkw84gwACgkQ+/8gJfVrobKgrgCeMQ8WNJRAiiZABP5N+PSz/gHX
    PmYAniP9otwBOF68h+npy0DXv51z8pTN
    =8nta
    -----END PGP SIGNATURE-----
    Kenny Meyer, Jul 13, 2010
    #6
  7. Kenny Meyer

    Kenny Meyer Guest

    On Jul 13, 4:14 pm, Hans Mulder <> 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.
    Kenny Meyer, Jul 14, 2010
    #7
  8. 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


    -----BEGIN PGP SIGNATURE-----
    Version: GnuPG v2.0.10 (GNU/Linux)
    Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

    iEYEARECAAYFAkw+IRwACgkQRIVy4fC+NyT+EgCgg3fJy58fMnK9Y/HvBe6HzLtU
    sRQAnAr1vr7cLsei1eDS6Yr6deolMLeL
    =SnuZ
    -----END PGP SIGNATURE-----
    Steven W. Orr, Jul 14, 2010
    #8
  9. On 2010-07-14, Steven W. Orr <> 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
    Grant Edwards, Jul 14, 2010
    #9
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Tomasz Judycki

    Socked not valid - how to check it?

    Tomasz Judycki, Mar 3, 2004, in forum: Perl
    Replies:
    0
    Views:
    475
    Tomasz Judycki
    Mar 3, 2004
  2. Shapper
    Replies:
    4
    Views:
    9,317
    leotiger
    Sep 20, 2006
  3. juppie
    Replies:
    5
    Views:
    30,994
    juppie
    Aug 30, 2006
  4. G Fernandes
    Replies:
    9
    Views:
    589
    DHOLLINGSWORTH2
    Feb 27, 2005
  5. Manuel
    Replies:
    4
    Views:
    449
    Manuel
    Jan 9, 2006
Loading...

Share This Page