frazzled
frazzled

Reputation: 21

Match Substring from Command Output

There are some close candidates for this question having already been answered, and I've tried several methods of trying to solve the issue. Specifically, my scenario is this:

I have an array of utility names that may or may NOT be installed on a linux machine (e.g.: ssh, sudo, etc.), so I am trying to check if the utility exists or not based on the result of trying to invoke the utilities in turn. I'm trying to do this in bash. Bash version is 4.1.5(1) running on Ubuntu 10.10 but planned to deploy on BusyBox.

If the utility doesn't exist, then usually you get a message saying "not found" or it includes that exact string. Otherwise you get a usage message. I have tried some regex expressions for the grep I use, but it hasn't made any difference, which leads me to believe there is something more fundamentally flawed with my code.

I am fully aware there are utilities that do this, but with the environment I am working in I do not have access to things like dpkg to check utilities/packages. In short, the environment I plan to deploy this on has NO PACKAGE MANAGEMENT.

What I have roughly goes like this:

#!/bin/bash
TOOLS=( 'ssh' 'soodo' 'dhclient' 'iperf')
#list of tools is abridged for convenience and added 'soodo' as a sure miss

#add a ridiculous option flag so don't accidentally trip any real flags
if `echo ${TOOLS[0]} -222222 | grep -q "not found"`; then
echo "${TOOLS[0]} is not installed."
else echo `${TOOLS[0]} --version`

#I am aware that --version is not applicable for all utilities, but this is just
#for sake of example.

My problem is that the if never seems to be accurately picked up. If I tweark ` marks around it either creates false positives or false negatives on the if (e.g.: a program like soodo will be claimed to exist when it doesn't, and something like ssh will be reported as not installed even though it is).

If you guys need any further clarification on what I'm trying to do or the like, please ask. It's the least I can provide back in exchange for some insight by others.

Upvotes: 2

Views: 540

Answers (2)

glenn jackman
glenn jackman

Reputation: 247062

For bash, type is the way to determine if a command is a program in your PATH, or a function or an alias.

TOOLS=( 'ssh' 'soodo' 'dhclient' 'iperf')
for tool in "${TOOLS[@]}"; do
  if type -p "$tool" > /dev/null; then
    echo "$tool is installed"
  else
    echo "$tool is not installed"
  fi
done

The errors in what you're doing:

if `echo ${TOOLS[0]} -222222 | grep -q "not found"`; then

What's happening there:

  • first, echo ${TOOLS[@]} -222222 prints "ssh -222222" to stdout
  • that pipes into grep -q "not found" which prints nothing to stdout
  • the backticks substitute the output from the pipeline (a blank line, which is always the output from grep -q) into the if command, so you get if <a newline> ; then

You'll get the same result as if $(printf "\n"); then echo Y; else echo N; fi which is always true.

To do what you're attempting, you'd have to write:

if "${TOOLS[0]}" -222222 2>&1 | grep -q "not found"; then ...

That will execute the pipeline and then if will consider the exit status. Exit status zero is considered true, any other exit status is considered false.

However, don't do this to find out if a program exists.

Upvotes: 1

Ryan Stewart
Ryan Stewart

Reputation: 128899

#!/bin/bash
TOOLS=( 'ssh' 'soodo' 'dhclient' 'iperf')
#list of tools is abridged for convenience and added 'soodo' as a sure miss

for TOOL in ${TOOLS[@]}
do
  which $TOOL > /dev/null
  RESULT=$?
  if [ $RESULT -eq 0 ]
  then
    echo $TOOL is available
  else
    echo $TOOL is not available
  fi
done

Upvotes: 1

Related Questions