2

I currently have the command:

command -v gpg 2>/dev/null || { echo "Cound not find gpg. Aborting."; }

I'd like for instead of it redirecting the output to /dev/null, I'd like to display a message stating the output of the command and afterwords found!.

I.e.

  • If gpg is not found: Cound not find gpg. Aborting.
  • If gpg is found: gpg found at /usr/local/bin/gpg
  • 2
    Why are you using the { } group command there? It doesn't do anything useful in your example. – terdon Jul 21 '17 at 8:08
  • @Zanna You are actually correct. Overlooked that. It doesn't output anything. – Karl Morrison Jul 21 '17 at 8:10
5

The simplest approach would be something like this:

command -v gpg &>/dev/null && 
    echo "gpg found at  $(command -v gpg)" || 
    echo "Cound not find gpg. Aborting."

Of course that is not very elegant since it needs to run command twice. An alternative would be:

gpg=$(command -v gpg 2>/dev/null) && 
    echo "gpg found at $gpg." ||
    echo "Cound not find gpg. Aborting."
  • AFAIK, if command -v gpg doesn't find gpg, it won't output anything, so why discard error? – Samuel Jul 21 '17 at 15:13
  • @SamuelSantana why not? Maybe a future implementation of command will print something to stderr. You have nothing to lose with the redirection and it might make it more robust. Also, consider a case where you try this on a shell that doesn't have command. I can't think of one where this syntax is valid, but there may be some out there. Just a case of better safe than sorry. Also, it's how the OP originally had it :) – terdon Jul 21 '17 at 15:28
  • True, a future implementation could do that, but regarding your second point, in a case were command doesn't exist or simply fails, discarding the error may misinform you: gpg exists but command failed because -v isn't supported (before POSIX:2008 support for command's -v option wasn't required, so systems/shells which throw an error on command -v may exist); this would lead you to think gpg doesn't exist. Also, in the first example you would also need to redirect differently: >/dev/null 2>&1, though, realistically, one would use the second example's instruction, not the first's. – Samuel Jul 21 '17 at 17:17
  • @SamuelSantana why would I need to redirect differently? The 1st example is the non-portable, bash specific implementation of the OP's original. In bash, &>/dev/null is the same as >/dev/null 2>&1. – terdon Jul 21 '17 at 17:19
  • I know it is valid for bash and the question asked about bash, but you mentioned other shells. Sorry for not being clear about that, I had no more space left! Heh :) – Samuel Jul 21 '17 at 17:22
2

This would do the trick:

command -v gpg &>/dev/null && echo "gpg has been found at $(which gpg)" || 
{ echo "Cound not find gpg. Aborting."; }
1

Although the accepted solution by terdon♦ is brief and pretty, I would suggest something like:

cmd_exists() {
  (
    unalias "$1" 2>/dev/null
    status=$(command -v "$1")
    case $status in
      *"$1") echo "$1 found at $status";;
      "") echo "Could not find $1. Aborting."; return 127;;
      *) echo "Error: $status" >&2; return 1;;
    esac
  )
}

cmd_exists gpg

It deals with two cases not dealt by the other method's here:

  1. Aliases: they may hide an executable, but my function gives you the actual path to the executable only if there is one. The other methods will give you the alias definition and return a zero exit code, whether an actual command exists behind it or not.

  2. Better error handling: Exit code 127 stands for "Command not found" type of errors, so you can have separate error handling for when a command is not found and when some other error occurs.

    If there is some imponderable error (that is, an unknown error apart from the command not being found), it doesn't hide it, misleading you into thinking gpg doesn't exist when it may. If you want to discard this errors, then call it like:

    cmd_exists gpg 2>/dev/null


Notes:

Regarding aliases, this may or may not be what you want, e.g. knowing an alias exists may be enough for you.

Unalias happens inside a subshell, so it won't mess your working shell's aliases.

Regarding error handling, I'm not a shell scripting expert, so I wouldn't know how likely an error would be in this situation nor if there's a better way to handle them.

So beware, this might be overkill.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.