Skip to content

Instantly share code, notes, and snippets.

@bahamas10
Created May 22, 2014 20:06
Show Gist options
  • Select an option

  • Save bahamas10/beaade5081474c526f01 to your computer and use it in GitHub Desktop.

Select an option

Save bahamas10/beaade5081474c526f01 to your computer and use it in GitHub Desktop.
command command

command is a bash-builtin, that allows for finding aliases and functions (which may or may not use programs installed in $PATH).

$ type -a command
command is a shell builtin
command is /usr/bin/command
dave @ [ bahamas10 :: (Darwin) ] ~ $ command -v colordiff # a function
colordiff
dave @ [ bahamas10 :: (Darwin) ] ~ $ command -v chomd # an alias
alias chomd='chmod'

So, to get the output we want we need to call the command line tool explicitly. Since that's bad practice, we should use the command command.

dave @ [ bahamas10 :: (Darwin) ] ~ $ command command -v colordiff
colordiff
dave @ [ bahamas10 :: (Darwin) ] ~ $ command command command -v colordiff
colordiff

??? the command command still calls the builtin, and never the command intalled on the operating system.

@bahamas10
Copy link
Copy Markdown
Author

in response to @dualbus on https://twitter.com/bahamas10_/status/469529051443789824

[[ -x $(command -v foobar ]]

this can still be fooled, albeit in a highly contrived manner.


1 make a file in your cwd, which is NOT in your $PATH, that has executable permissions

$ export PATH=/bin
$ pwd
/home/dave
$ touch foobar
$ chmod +x foobar

2 ensure the command does not show up when running the command -v command (this is expected and proper)

$ command -v foobar; echo $?
1
$ [[ -x $(command -v foobar) ]]; echo $?
1

3 define a function with the same name as the executable file in your cwd, foobar

$ foobar() { do_something; }
$

4 observe that the check returns successful, even though there is no program named foobar in your $PATH

$ [[ -x $(command -v foobar) ]]; echo $?
0

@dualbus
Copy link
Copy Markdown

dualbus commented May 25, 2014

You are right, there are some edge cases with command, so a custom look-up function might be better. Though, in the end, command is directly related with how the shell looks for commands, so in some cases your custom function might work, but the shell might still not be able to call the command.

I thought about two workarounds:

  1. path=$(unset xyz; command -v xyz); [ -x "$path" ]; echo $?
  2. path=$(command -v xyz); case $path in */*) :;; *) ! :;; esac && [ -x "$path" ]; echo $?

The 1st seems to be better, because unset func seems to work in all shells well, whereas checking for slashes in the output of command seems to be pretty inconsistent from shell to shell (see: https://gist.github.com/dualbus/96dc83c9d8d306da42eb). I'm not sure if also putting an unalias xyz there is useful.

Note: beware of using path as a variable in zsh, it behaves weirdly: https://gist.github.com/dualbus/31dee9ce487ba64413a5

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment