1

I'm writing a little script that, prior to doing anything, checks to see if certain required software is installed, and either bombs out or reconfigures itself not to require the missing applications. Currently it does this by seeing if a call to 'which' succeeds.

Obviously, since this is critical infrastructure, it would be nice to test that this functionality works reliably (to give some idea how critical, two of the applications I'm checking for are 'cowsay' and 'fortune'). Can anyone think of a way, short of either uninstalling or renaming, that I can temporarily fool 'which' (or some other command if there is one which would could be used to achieve what I want), into thinking something is not installed?

I think this might be useful to me in other projects which my employers would feel are almost as valuable to the enterprise as this one.

Thanks in advance!

hardcode57
  • 1,497
  • 2
  • 11
  • 10
  • 1
    You can temporarily change the PATH to hide the binaries you are interested in and restore it afterwards. – Poshi Apr 25 '19 at 11:55
  • That wouln't allow me to test for combinations where they are not all missing, when the binaries are all in e.g. /usr/bin – hardcode57 Apr 25 '19 at 11:58
  • 2
    Use a temporary binaries folder and alter the `PATH` to point to it. Create soft links in that folder that points to the required binaries and leave out the tested ones. – Poshi Apr 25 '19 at 12:07
  • Ah! yes, that will work! Thanks.Very soon I will have the ability to have a cow read out fortune cookies at random intervals on any terminal in the building. Next stop world domination! – hardcode57 Apr 25 '19 at 13:13
  • If it's critical infrastructure, you should be ensuring the necessary dependencies exist when you *install* the program, not when you try to run it. This is what package managers are for. – chepner Apr 25 '19 at 19:30
  • That is, it should be impossible (or very difficult) to install your program without also installing the dependencies, and likewise it should be difficult or impossible to remove the dependencies without also removing your program. This way, you *know* that if your program is installed, so are its dependencies, and therefore your program is safe to run without any runtime checks. – chepner Apr 25 '19 at 19:33

1 Answers1

0

One way to do what you want is to define a which function that pretends that some tools are not installed. Bash doesn't look for a command on the PATH if it finds a function with the name. Assuming that your program is called 'myprog', this Shellcheck-clean code demonstrates the idea:

#! /bin/bash -p

function which
{
    local -r prog=$1

    case $prog in
        cat)    return 1;;
        grep)   return 1;;
        *)      command which -- "$prog";;
    esac
}

export -f which

bash myprog arg1 arg2
  • The which function returns non-zero status (1) for cat and grep (as examples), making it look like they are not installed.
  • The which functions uses the builtin command to run the real which for other inputs. Since that is the last thing done in the function, the exit status of the real which will be used as the return status of the which function.
  • export -f which exports the function so it is defined in Bash programs that are run from the current shell (or its children, etc.). In this case it means that the function will be defined in 'myprog'.
  • Running the program explicitly with Bash (bash myprog ...) instead of running it directly (./myprog ...) means that the exported function trick will work even if myprog uses the -p option on the shebang line.
    (Using -p on the shebang line reduces the risk that Bash programs will malfunction due to unusual things in environment variables or personal configuration files. For instance, it makes Bash programs immune to the Shellshock bugs related to exported functions with all versions of Bash.)
  • Note that it's generally better to use the Bash builtin type command instead of the external which command. See How to check if a program exists from a Bash script?.
pjh
  • 6,388
  • 2
  • 16
  • 17