Search code examples
shellposixidioms

Running programs only if they are installed, and ignoring them otherwise


When writing shell scripts, is the an idiom or swift way to run a program only if it is installed, and if it is not, just let it be (or handle the error in some other way apart from installing it)?

More specifically, I have a lot of servers which I access over ssh, and whenever I get a new server, I simply copy all my rc-files to it. The .zshrc starts tmux unless it is already running. Some of the servers (not all) do not have tmux installed. I do not want to install it because of disk space limitations, I do not want to have different rc-files for different servers, and I do not want my rc-files to be interrupted when executing them.

I have seen solutions involving apt-cache policy <package-name>, so I guess I could use that and pipe it to something like grep -e 'Installed: (none)', but that would assume that the server is running Debian or Ubuntu, which I can not do, and it would only work for packages that were installed with apt, not things I have installed in other ways.


Solution

  • command -v <command> is the common (and POSIX) way to check if a command could be executed (is executable and on the $PATH).

    E.g:

    command -v tmux >/dev/null &&
      tmux a -t name
    

    (>/dev/null since, if the command exists, its path will be printed to STDOUT.)

    It could be nice to put it in a reusable function:

    maybe() {
      ! command -v "${1}" >/dev/null ||
        "$@"
    }
    

    Then one could use:

    maybe tmux a -t name
    

    And if tmux is available then tmux a -t name will be run, otherwise it’ll be silently ignored.

    Or, if you want some feedback when a command is not available:

    maybe() {
      if command -v "${1}" >/dev/null
      then
        "$@"
      else
        printf 'Command "%s" not available, skipping\n' "${1}" >&2
      fi
    }