Search code examples
linuxbashalias

bash alias to run command (with args) if exist or run another command (with args) otherwise


I want to setup bash alias that runs command_1 [args] if command_1 exists and "runnable", or runs command_2 [args] if command_1 does not exists or not "runnable". [args] are not known in advance and could be empty or not. [args] are the same for command_1 and command_2.

In the terminal I can action like this:

command_1 --version >/dev/null 2>&1
[ "$?" = "0" ] && command_1 args || command_2 args

The first line outputs nothing, the second checks exit code ($?) of first line. So if command_1 --version exits with "0" status code (without errors), I run command_1 args, else (if command_1 doesn't exists or is broken by any other reason, e.g. user don't have relevant permissions to run command_1) I run command_2 args.

How to turn this into bash alias?

If there were no [args] I could use something like this:

alias my_alias='command_1 --version >/dev/null 2>&1 ; [ "$?" = "0" ] && command_1 || command_2'

But in this case if I run my_alias args and command_1 exists, It will run command_1 without args. How to add [args] into my alias for both command_1 and command_2?


Solution

  • This may be an XY problem, because an alias is a poor match for the purpose. Use a function instead:

    resolve_command() {
      if type 'command_1' 1>&2; then
        'command_1' "$@"
      elif type 'command_2' 1>&2; then
        'command_2' "$@"
      else
        echo 'Nope. Blah.' 1>&2
        return 11
      fi
    }
    
    resolve_command "${some_args[@]}"
    

    This can be easily extended to probe for an arbitrary number of different commands.

    resolve_command() {
      local -ar commands=('command_1' 'command_2' 'command_3')
      local cmd
      for cmd in "${commands[@]}"; do
        if type "$cmd" 1>&2; then
          "$cmd" "$@"
          return
        fi
      done
      echo 'Nope. Blah.' 1>&2
      return 11
    }
    
    resolve_command "${some_args[@]}"