LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   Shell Script 101: TEST (https://www.linuxquestions.org/questions/programming-9/shell-script-101-test-932466/)

leslie_jones 03-03-2012 03:45 AM

Shell Script 101: TEST
 
I feel a bit embarrassed to ask this having been a Linux user for over 10 years - but I've never really dug deep into shell scripting.

One of the log rotate scripts on a small gateway contains this:

Code:

prerotate
    test ! -x /usr/sbin/sarg-reports || /usr/sbin/sarg-reports
endscript
postrotate
    test ! -e /var/run/squid.pid || /usr/sbin/squid -k rotate
endscript

Is my understanding flawed?

I'm assuming that if the prerotate line returns true that the postrotate section will run. If not the 'endscript' will terminate it?

I'm assuming the truth of prerotate is negated with ! and what that line basically says is if /usr/sbin/sarg-reports is not executable ... then I struggle to get the logical || or with just the file name.

If I could understand the purpose of the || or, I think I'd 'get it' and the postrotate line.

Be gentle with me, I'm ashamed enough that I don't know. Google has been little help to me (|| seems to upset it)

firstfire 03-03-2012 03:56 AM

Hi.

Command
Code:

test ! -x /usr/sbin/sarg-reports || /usr/sbin/sarg-reports
checks if /usr/sbin/sargs-reports is executable by you and, if so, executes it.

Quote:

Originally Posted by `man bash'
An OR list has the form

command1 || command2

command2 is executed if and only if command1 returns a non-zero exit status. The return status of AND
and OR lists is the exit status of the last command executed in the list.

Exit status of
Code:

test ! -x file
is 1 if `file' is executable by you.

cin_ 03-03-2012 03:57 AM

bash ||
 
Google likes ` bash || `.

It is an OR operator.

Dark_Helmet 03-03-2012 04:01 AM

What you're seeing is the original developer taking advantage of "short circuit" boolean evaluation.

You have two basic boolean operations where this comes into play: logical AND (&&) and logical OR (||).

If you have a statement such as "alpha && beta" then alpha must evaluate to true and beta must evaluate to true for the whole expression to evaluate to true. The point is that for logical AND, both alpha and beta must be evaluated to determine the overall expression.

Compare that with a statement such as "alpha || beta." There are three cases where the overall statement evaluates to true: (1) alpha = true; beta = false, (2) alpha = true; beta = true, (3) alpha = false; beta = true. Notice that if alpha evaluates to true, then it does not matter what beta evaluates to--the overall expression will still be true.

That's "short circuit" evaluation. The shell will evaluate only so much of the expression as is necessary to determine the overall result.

So, back to your code snippets, because they use ||, the second half of the statement will be ignored if the first half is true. Only when the first half evaluates to false will the second half get evaluated (which in this case is launching a new process).

EDIT:
It seems I was fashionably late to the party :)

leslie_jones 03-03-2012 04:03 AM

Thank you. Much appreciated. Man Bash. Dear oh dear. How did I miss that.....
{head held in shame}

leslie_jones 03-03-2012 04:13 AM

Quote:

Originally Posted by Dark_Helmet (Post 4617406)
So, back to your code snippets, because they use ||, the second half of the statement will be ignored if the first half is true. Only when the first half evaluates to false will the second half get evaluated (which in this case is launching a new process).

So let me see if I've got this clear when the left hand side of the or is false (that is I can't execute it).
Code:

test ! -x /usr/sbin/sarg-reports || /usr/sbin/sarg-reports
The right hand side would evaluate, but because I have no permissions to execute I presume it would dump an error to stderr. So in effect it does nothing. However, I'm guessing the exit code won't be zero meaning that 'endscript' will fire and postrotate won't ever run. Does that sound like I've got it? I think I'll have a play and see - just to be clear.

Quote:

Originally Posted by Dark_Helmet (Post 4617406)
EDIT:
It seems I was fashionably late to the party :)

Hell, how can you be late? the DJ hasn't even turned up yet!

Sincere thanks to all. Kicking myself.

Dark_Helmet 03-03-2012 04:21 AM

And this is the cue for the entrance of the double-negative that is Unix process exit codes.

firstfire correctly stated that:
Code:

test ! -x file
returns 1 if you have execute permissions.

What you have to remember is, for Unix process exit codes, 0 is "success" or "true." A non-zero value is "failure" or "false."

That's the exact opposite of programming languages like C.

So, just to step through:

assuming you have execute privileges on the file
Code:

test -x file
will return 0 (i.e. "true")

Code:

test ! -x file
will return 1 (i.e. "false")

Because the left half evaluates to "false," the right half is evaluated--and hence, spawns the process.

EDIT:
And as for my being late, I must be, because firstfire and cin_ were already on the dance floor ;)

firstfire 03-03-2012 04:26 AM

Equivalent command using AND (&&) operator would be
Code:

test -x /usr/sbin/sarg-reports && /usr/sbin/sarg-reports
To play with the logic, try something like
Code:

$ test  -x `which bash` && echo yes || echo no
yes


cin_ 03-03-2012 05:16 AM

as led Isadora Duncan's, My Life
 
Quote:

If my virtue be a dancer's virtue, and if I have often sprung with both feet into golden-emerald rapture, and if it be my Alpha and Omega that every thing heavy shall become light, every body a dancer and every spirit a bird: verily, that is my Alpha and Omega.
Nietzsche, Thus Spoke Zarathustra

leslie_jones 03-03-2012 06:06 AM

Quote:

Originally Posted by Dark_Helmet (Post 4617416)
And this is the cue for the entrance of the double-negative that is Unix process exit codes.
.....
What you have to remember is, for Unix process exit codes, 0 is "success" or "true." A non-zero value is "failure" or "false."

That's the exact opposite of programming languages like C.

That clears something up for me as I tend to think in C true 1 /false 0 in my head. But I'm really confused now! I figured 'experiment will solve this for me', but hell no! Let me step through, perhaps someone will spot my logic flaw and bomb.

I created a simple 'hello world' shell script and did NOT add execute to it. Testing with the example firstfire gave (modified) it seems to be the exact opposite of what I would expect.

Code:

$ test -x `/home/leslie/scripts/hello.sh` && echo yes || echo no
-bash: /home/leslie/scripts/hello.sh: Permission denied
yes

I don't have execute permissions and I read this evaluation using true = 0 and false =1 for shell, AND, I'm guessing that the exit code of 'echo yes' would be true/0. This may be a fatal flaw, but I'd expect an echo to complete with a return code of zero (true in shell).

If I don't have execute permissions test -x the result should be 1/false in shell speak. The other side of the AND is echo yes and fires because the return code 1 (a double bluff here) is logically 'true' and evaluation of the && clause continues - firing the echo. However, as I see it the shell would return '0' (true) for the echo statement, meaning the && as a whole should fail??? 1&&0 is not true???? Therefore the whole clause fails and the || or should be evaluated printing the 'no' to the screen - but this does not happen?

Clearly I'm wrong as 'no' never prints. If I invert the test
Code:

$ test ! -x `/home/leslie/scripts/hello.sh` && echo yes || echo no
-bash: /home/leslie/scripts/hello.sh: Permission denied
no

Am I right to be confused here?? I know that outside of logical malarky:

Code:

#!/bin/sh
if [ -x /home/leslie/scripts/hello.sh ]
then
    echo "is executable"
else
    echo "is not executable"
fi

Works as any sane rookie would expect it to work.

Somewhere, something in my brain is broken, can you help me fix it!

Quote:

Originally Posted by Dark_Helmet (Post 4617416)
EDIT:
And as for my being late, I must be, because firstfire and cin_ were already on the dance floor ;)

Magic, I can't trump that :-) Only to say for a good conga you need lots of people!

leslie_jones 03-03-2012 06:17 AM

Hang on! I'm being a divvy....

Quote:

If I don't have execute permissions test -x the result should be 1/false in shell speak. The other side of the AND is echo yes and fires because the return code 1 (a double bluff here) is logically 'true' and evaluation of the && clause continues - firing the echo. However, as I see it the shell would return '0' (true) for the echo statement, meaning the && as a whole should fail??? 1&&0 is not true???? Therefore the whole clause fails and the || or should be evaluated printing the 'no' to the screen - but this does not happen?
Of course it wont. 1&&0 is not true, sure. But the exit code will be a big fat 1 for shell (it's false) not a zero (this is not C). Hence the or IS satisfied.

Funny what a cup of tea will do!

Thanks to all. Finally....... derrrrrrrr.

catkin 03-03-2012 06:27 AM

Quote:

Originally Posted by Dark_Helmet (Post 4617406)
If you have a statement such as "alpha && beta" then alpha must evaluate to true and beta must evaluate to true for the whole expression to evaluate to true. The point is that for logical AND, both alpha and beta must be evaluated to determine the overall expression.

Only if alpha is true. From http://www.gnu.org/software/bash/man...nal-Constructs: "The && and || operators do not evaluate expression2 if the value of expression1 is sufficient to determine the return value of the entire conditional expression".

catkin 03-03-2012 06:35 AM

Quote:

Originally Posted by leslie_jones (Post 4617395)
Code:

prerotate
    test ! -x /usr/sbin/sarg-reports || /usr/sbin/sarg-reports
endscript
postrotate
    test ! -e /var/run/squid.pid || /usr/sbin/squid -k rotate
endscript


AFAIK, under bash test ! -x /usr/sbin/sarg-reports || /usr/sbin/sarg-reports is functionally identical to the more natural test -x /usr/sbin/sarg-reports && /usr/sbin/sarg-reports.

I cannot think why the programmer chose the more convoluted form.

Dark_Helmet 03-03-2012 11:44 AM

Quote:

Originally Posted by catkin
Only if alpha is true.

I just KNEW somebody was going to call me on that! :)

Yes, my original description was incomplete.

If the first/left half of a logical AND evaluates to false, the second/right half will not be evaluated--because there is no value for that portion which could make the entire statement evaluate to true.

Sorry to anyone if my haphazard response caused confusion.

And I gotta say, this is turning out to be a decent conga line.


All times are GMT -5. The time now is 06:44 AM.