-1

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?

AntonioK
  • 440
  • 6
  • 20

1 Answers1

1

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[@]}"
Andrej Podzimek
  • 2,409
  • 9
  • 12
  • 1
    `which` isn't an appropriate choice in bash -- unlike zsh where it really is built-in, it's an external command, not built into the shell. The POSIX equivalent is `if command -v command_1 >/dev/null 2>&1; then ...`, or the bash-only equivalent is `if type command_1 >/dev/null 2>&1` – Charles Duffy Aug 30 '23 at 13:38
  • 1
    Also think about using a different stand-in, since `command` itself is a command that's built into the shell (which is how I'm using it above -- when I say `command` I actually mean `command`, not `your-command-here`, whereas `command_1` is a `your-command-here`-type standin). Using the name `command` to also mean "insert your own thing here" is thus confusing. – Charles Duffy Aug 30 '23 at 13:38
  • @CharlesDuffy Edited. As for the `1>&2`, that’s intentional (to see what it resolved to without interfering with the actual command’s stdout). Of course the OP can go for a `>/dev/null` if this is not desirable. (Actually, `type` outputs something on failure, so an extra `2>&1` would be needed too to silence it.) – Andrej Podzimek Aug 30 '23 at 13:44