7

Using Terminal, what's the easiest way to determine if a binary named dcmdump is installed on the user's system? If installed I need to know its location (e.g. /usr/local/bin) and if its not installed then I'd like the Terminal to echo FALSE.

I know very little Terminal script but typing:

command -v dcmdump

Outputs the directory dcmdump is installed in (if installed - which is great) but nothing is echoed if its not (I want it to echo the string FALSE)

msw
  • 42,753
  • 9
  • 87
  • 112
Garry Pettet
  • 8,096
  • 22
  • 65
  • 103
  • 2
    "*but nothing is echoed if it's not*" -- and that's how you can tell it's not installed. Why is printing `FALSE` more useful? Incidentally, Terminal is just a terminal enumerator; it just lets you enter and display text. It's the shell that provides the ability to actually do stuff. – Keith Thompson Sep 26 '15 at 20:55
  • 1
    possible duplicate of [Check if a program exists from a bash script](http://stackoverflow.com/questions/592620/check-if-a-program-exists-from-a-bash-script) – Daniel Kamil Kozar Sep 26 '15 at 23:01
  • 1
    Are you planning on running the command if it *is* installed? If so, it's easiest to just try to run it, and if the exit status is 126 or 127, tell the user to install it and exit. – chepner Sep 27 '15 at 02:25

4 Answers4

9

You can use this:

$ which dcmdump 2>/dev/null || echo FALSE

Here is how it works:

  • The entire expression is a boolean OR (written as ||) of two commands. The left-hand-side of the OR is the command which dcmdump 2>/dev/null, the right-hand-side is echo FALSE.
  • Thanks to lazy evaluation (or short-circuiting), if the left-hand-side evaluates to “true” (or “success”), then the right-hand-side will not be evaluated. Otherwise, it will.
  • The command which NAME looks for an executable named NAME in your current shell $PATH. If it finds one, it prints its absolute path to the standard output and exits with a status indicating “success”, otherwise, it might or might not print an error message to the standard error output and returns a status indicating “failure”.
  • Since we don't want which's error message but our own, we redirect which's standard error output to the black hole /dev/null with the 2>/dev/null part.
  • The command echo TEXT simply outputs TEXT to the standard output. If you wanted FALSE to be printed to the standard error output, you could redirect it using echo FALSE >&2.
5gon12eder
  • 24,280
  • 5
  • 45
  • 92
5

On OS X at least, doing which dcmdump to have it say /usr/local/bin/dcmdump (if it finds the command) is not absolutely bad. But there can be issues with using which in other environments.

But the main ding against which in general is, it’s a separate command that’s not built into the shell, and so-called shell “builtins” are better choices when they get the job done just as well.

So if all you want is to check if a command exists (and don’t need to know where it is), you can get that just with the hash dcmdump builtin and examining the return value; e.g., echo $?, or:

if hash dcmdump 2>/dev/null; then
  echo "OK, you have dcmdump installed. We’ll use that."
else
  echo "You need dcmdump. I can install if for you, OK?"
  read -e -p "Y or N? " yn
  if [[ "y" = "$yn" || "Y" = "$yn" ]]; then
    ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
    brew install dcmtk
  else
    echo "We need dcmdump. Stopping."
    exit
  fi
fi

None of the options for checking command existence return a literal string FALSE (as you ask in your question); but using hash dcmdump and just checking the return value will get the job done.

And if you do want to know where exactly the command is, that’s what command -v will give you. Using type dcmdump will also give you that info, in a slightly different form.

Anyway, hash and command -v and type are all shell built-ins, so that’s in part why they’re recommended over which for this. The canonical answer on this at SO gives more details.

btw, if your goal is to get dcmdump on your system, you can do that by installing homebrew:

ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

And then after that, you can install the dcmtk package:

brew install dcmtk

And then you really will have a dcmdump command in /usr/local/bin/dcmdump.

Community
  • 1
  • 1
sideshowbarker
  • 81,827
  • 26
  • 193
  • 197
  • I've seen on SO that using the `which` command is not a good idea hence why I thought the `command -v` approach is better. Problem is, I have no idea how to do an if...else clause in the Terminal – Garry Pettet Sep 26 '15 at 20:42
  • Ah, about that, actually, using `hash` is best. I’ll update my answer. – sideshowbarker Sep 26 '15 at 20:47
  • Thanks for the explanation on getting dcmtk - figured that out yesterday (took ages!). I actually need a way to check if a user has installed dcmtk on their system (if not, my app will prompt them to). – Garry Pettet Sep 26 '15 at 20:58
1

You can use which and check if the return value is null like bellow:

#!/bin/sh
bi=$(which $1)
if [ -z $bi ]
then
    echo "FALSE"
else
    echo $bi
fi

Then the script can be run like this:

./script command

AKJ88
  • 713
  • 2
  • 10
  • 20
1

POSIX compatible:

command -v dcmdump || echo FALSE

or use the below if you need to reuse the path

if cmd=$(command -v dcmdump); then echo $cmd; else echo FALSE; fi
martin
  • 862
  • 9
  • 28