SuSE 11.1 'which' is too verbose

Hi

I noticed that the output of the ‘which’ command changed with SuSE-11.1. When looking up a non-existing command the traditional response was <nothing> (just empty string).

Now it returns the paths searched:

> which foobar
which: no foobar in (/usr/lib/mpi/gcc/openmpi/bin:/home/tsp/bin:/usr/local/bin:/usr/bin:/bin:/usr/bin/X11:/usr/X11R6/bin:/usr/games:/usr/lib/mit/bin:/usr/lib/mit/sbin:/opt/kde3/bin)

This is a severe problem, because it breaks a lot of scripts which checked for the existence of other tools and checked if the response was empty.

Is there any way to restore the traditional behaviour?

Just throw away the error output:

which foobar 2>/dev/null

BTW, since that error output is actually going to stderr, it should not break any scripts, it just shows up on your screen if not redirected.

Hi ken

Sorry, but that would mean to change all existing shell scripts (and there are a lot). ‘which’ is one of the very basic scripting commands like sed and awk and it must behave the same way on all releases and architectures.

So my only option seems to be setting a system wide alias on all installs of 11.1. What do you think?

Unfortunately not so.

#!/bin/sh
RESULT=$(which foobar)
if test -n "$RESULT" ; then
      echo $RESULT
fi
exit 0

will show the whole error message. :frowning:

No your methodology is faulty. Try this:

#!/bin/sh
RESULT=$(which foobar)
if test -n "$RESULT" ; then
      echo RESULT is non-empty
fi
exit 0

Also note that $() is a bash construct so you really should put #!/bin/bash at the top of the script.

ken_yap wrote:

No your methodology is faulty. Try this:

Ok, I got it. Thanks for insisting on this point. The variable will be empty when the file is not found.

This still leaves the problem of an error message going to the screen for something which is not really an error condition. This will clobber my dialog window.

The following seems to work:

#!/bin/bash
which () {(alias; declare -f) | /usr/bin/which "$@" 2>/dev/null;}
export -f which
RESULT=$(which foobar)
if test -n "$RESULT" ; then
    echo -e "Found: $RESULT"
else
    echo "foobar is missing"
fi
exit 0

Will I break something when setting this system wide?

No idea, but I doubt it will hurt any scripts, only interactive users of which.

Ok, I will give it a try. I am the only interactive user anyway who loves to work on the command line.

Thank you for the help.

openSUSE 10.3 here:

henk@boven:~> which aap
which: no aap in (/opt/kde3/bin:/home/henk/bin:/usr/local/bin:/usr/bin:/bin:/usr/bin/X11:/usr/X11R6/bin:/usr/games:/usr/lib/jvm/jre/bin:/usr/lib/mit/bin:/usr/lib/mit/sbin)
henk@boven:~>

So at may be new to you in 11.1, but the change must be earlier.

And indeed the message goes to stderr, so it should be

RESULT=$(which foobar 2>/dev/null)

which is good programming practice when you only want to test stdout.

hcw wrote:

So that may be new to you in 11.1, but the change must be earlier.

You are right. Some of my bash scripts are quite old and I just noticed some differences when trying them on a new box with 11.1. Digging back into history turned out that way back in SuSE-8.2 the which command was an alias by default:

> alias | grep which
alias which='type -p'

This explains the different behaviour. I really overlooked this.

By the way: output of wc changed with coreutils release 5.0.90 (quite annoying when scripts should be compatible)

SuSE-8.2:

> echo -e "


" | wc -l
      4

SuSE-11.1:

> echo -e "


" | wc -l
4

There can be unpleasant surprises when one upgrades indeed.

BTW, the 11.1 type of output of *wc *is also the 10.3 output.

I personaly do prefer

wc -l | read NUMBER

over

NUMBER=$(wc -l)

because *read *skips the surrounding white space.
(But now, as I try this, it does not work in *bash *allthough it is according to the *man *page. When I use *ksh *for the same construct it works?!?!?!? Never mind I do prefer *ksh *over *bash *anyway :slight_smile: )