Solved Can't get 'if' working in shell script

I'm unable to get this working:-

Bash:
if [ping -c3 `mount | grep net | cut -f 1 -d :`]
    then echo 'working...'
fi

This is what I get:-

sh: [ping: not found

This, on its own works fine:

Bash:
ping -c3 `mount | grep net | cut -f 1 -d :

There's probably something obviously wrong, but haven't figured it out so far....

Any suggestions?
 
It needs a space between [ and ping and also between ` and ].

Well, try:
Code:
if [ ping -c3 `mount | grep net | cut -f 1 -d :` ]; then
    echo 'working...'
fi
 
Suggestion: Instead of blindly adding a space after the [, or getting it to work without the [ ], try to understand why it was broken, and why it works now. I'm just going to give you a few hints.

Shells rely heavily on special characters, let's call them "punctuation". For example, 'xxx yyy' means take xxx yyy literally as a single token, and limit the substitution operations within the single quotes. A similar example is "xxx yyy", except that here the set of substitution operations within the double quotes is different. The version `xxx yyy` looks syntactically similar, but has radically different semantics: take xxx yyy, run it as a command, and substitute the output of the command. Today, the use of `xxx yyy` is discouraged; shells instead offer the $(xxx yyy) syntax, which is thought to be clearer (your taste may vary).

But notice one thing: There are no spaces needed between the quote (whether single, double or back) and the thing next to it. Matter-of-fact, if you write something like x=`xxx` (set the variable x to the output of the xxx command), then you can't put any spaces around the = or before the `, it breaks it. Why? Because the shell treats "punctuation" characters (like quotes and =) differently, and the tokenizer splits around them. If you add spaces, you have extra tokens, which the shell executor then won't understand.

So far, so good. The next thing to understand is that [ is not punctuation. It is an executable (today usually implemented as a shell built-in). So for example x=`[ xxx ]` works, and absolute requires the space after the [ (but NOT before the `). Why? It literally just means: Set x to the output of running the [ program, with arguments xxx ] to that program. Is that terribly inconsistent? Why is [ an executable (which needs to be tokenized separately), why things like () are punctuation (which is auto-split during tokenization)? Because the original shell was a quick hack, the implementors took the shortcut of moving the implementation of the core of the if statement into a separate executable, which is really called test. Look it up sometime: /bin/[ and /bin/test are the same program!

Slight perversity: Today's [ program requires the last argument to be a ], while when called as test it actually rejects the ]. That may seem bizarre and inconsistent, but looking at the way [ is used in if statements of shell scripts, it achieves the desired goal of syntax checking, just in a hacky and unexpected way.

And finally, the way the if statement works. It is super simple: take the next thing after the if, and run it as an executable. If the result of running it is true, then take the branch after the then, if not the branch after the else (if present). In shell scripts, one often finds the construct if [ xxx yyy ] ; then foo ; fi. Here the xxx and yyy are some arguments that the [ command knows to use (for example if [ $x -eq 42 ] would test whether the integers x and 42 are equal). But if all the [ command is doing is testing whether the result of another command is true, then you are being redundant. That's why in your construct if [ ping ... ] you don't even need the [ command, although it usually doesn't hurt either.

In reality, to write shell scripts, one actually has to work how the shell works, and how it interacts with programs. Even to get the spaces around the punctuation right, one has to understand the implementation underneath it.
 
More problems with if

I'm trying find if a particular host is online, but can't get this to work
Code:
IP_MAC=`arping -i em0 -c1 00:23:24:64:bf:cc | sed -n /from/s/^.*from.//p | cut -w -f 1` >/dev/null 2>&1
echo $IP_MAC
if $IP_MAC -eq ''  ; then
echo 'server not available'
fi

I've tried $IP_MAC -eq '', $IP_MAC = '', also ' ' " ", but always get something like sh: =: not found
 
That's because of the redirect on line 1. What are you trying to do there?

It's similar to trying to do this:
Code:
FOO="BAR" > /dev/null 2>&1
It does not make sense.

And this is rather poor:
Code:
if $IP_MAC -eq ''  ; then
If $IP_MAC is empty the line ends up looking like this:
Code:
if -eq ''; then
Which is a syntax error.

This is much better:
Code:
if [ -z "$IP_MAC" ]; then

Code:
     -z string     True if the length of string is zero.
 
Back
Top