Posts tagged as '
&&operand ' ...

A short one for today, then it’s week-end and I will only post on Tuesday (Monday is holiday).

In a script, one of the things which is usually overlooked is the validation of variables. And if you are developing a library of functions (for scripts), it is simply forgotten most of the times. This is one of the reason you are not re-using the functions made by your fellow developers : if you want them to work for your specific purpose, you have to specify a thousand of options that you will never use.

How can you make a function using optional variables (meaning that it will resort to default ones when nothing is specified) without writing dozens of lines of code ?

By using the little trick described in this article. This is how you define a default variable usually :

D_LOG_LEVEL=9

if [ “$1” = “” ] #In case it is defined on the command line

then

LOG_LEVEL=${D_LOG_LEVEL}

else

LOG_LEVEL=$1

fi

Half your script went to write this wonderful code. Now, let’s make it faster.

First, we can replace the ifs with the one we’ve seen earlier this week :

D_LOG_LEVEL=9

([ “$1” = “” ] && LOG_LEVEL=${D_LOG_LEVEL}) || LOG_LEVEL=$1

Next step, we can get rid of the variable “D_LOG_LEVEL, as it is used only once.

([ “$1” = “” ] && LOG_LEVEL=9) || LOG_LEVEL=$1

Last step, let’s get rid of the not very nice “”=”” :

([ -z $1 ] && LOG_LEVEL=9) || LOG_LEVEL=$1

This allows you to define variable that are going to resort to default if it is not specified, without loosing too much time writing the code.

Note that if you define variables that need to be set before you send

([ -z ${LOG_LEVEL} ] && LOG_LEVEL=9)

Last thing about the variables in the function : You should test them before you run your function or script. This sounds obvious, but it is not usually the case (resulting is headache for people doing the support). If your script needs a filename as parameter and needs this file to exist, writing this line :

([ -z $1 ] || [ ! -f $1 ]) && (echo “File $1 Missing” && return 1)

is not going to take you much time and will help the next guy who is going to use your script.

Thank you for helping the Unix Scripting World to be a better place, and see you on Tuesday !

Tomorrow, we will talk about pipes (and file descriptors). But today, let’s talk about the other ways to chain commands.

One of the easy way for you to have to commands running one after the other, without you staying in front of the screen (see you at Starbucks), is to chain them using a semi-column :

RunVeryLongProcess;PrintReportOnVeryLongProcess;SendMailToBoss

Once you will have defined the commands “RunVeryLongProcess“, “PrintReportOnVeryLongProcess“, and “SendMailToBoss“, you will get a pay rise because the three jobs have been running one after the other, for 9 hours, and you have send a mail to your boss at 11pm ! How dedicated are you ! (At least to a Venti Macchiato :-)).

Yep, but what if RunVeryLongProcess fails ? Oops… You have send an empty report to your customer, and a mail to your boss saying that everything’s OK…

To avoid this, you can use the logic operators “and” (“&&”) and “or” (“||”), e.g.

RunVeryLongProcess && PrintReportOnVeryLongProcess && SendMailToBoss

Now, if “RunVeryLongProcess” or “PrintReportOnVeryLongProcess“, no mail will be sent to your boss. You might not be the employee of the week, but you will still have a job 🙂

This “and” operator means that if the first job succeeds, the next one will be kicked. The keyword here is if, as you can do the same with an if statement, like this :

RunVeryLongProcess

if [ $? -eq 0 ]

then

PrintReportOnVeryLongProcess

if [ $? -eq 0 ]

then

SendMailToBoss

fi

fi

I’m tired only to write this, and it is only for three processes ! So, you can now make an extensive use of the && operator.

You can also use it to replace an if statement

&& operator instead of if statement.

Let’s say you want to check the variable “a”, if it is set to “morning” you say hello, and if not, you say “goodbye”…

(you can write the if, i’ll skip it, i’m tired)

And using && operator :

([ “$a” = “morning” ] && echo “Hello” ) || echo “goodbye”

You must understand how this is working. It starts by executing the first function, in this case, a test :

[ “$a” = “morning” ]

Then, if the result is true (return code 0), it tries the other part of the equation, i.e. :

echo “hello”

If the first part of the equation is wrong, then there is no need to execute the second part. The block around the && operand will be false. It then goes to the third part, which is supposed to be executed if the && equation is false, i.e.

echo “Goodbye”

If you want to use this, you must be sure that whatever function or command you call (except the first part of course) is going to return 0. Otherwise, you can get strange results, as both the “then” and “else” commands will be executed.

There is a way to avoid it, but it is getting complicated :

([ “$a” = “morning” ] && (say “hello” || true)) || say “goodbye”

By doing this, even if the “say” function returns a non-zero status code, the “true” is executed. True always return “0” upon execution, so this is a way to avoid bizarre results.

This is the further you should go. Starting from this, there is no point to use the && operand anymore. Just write the if statement, and the guy fixing your script later will be thankful (and it might be you).

Regarding the order of execution, the parenthesis do not change it. The operations are executed from left to right.

(btw, the “say” command exists under Mac OS X and is quite fun).

That’s all for today. I hope you have enjoyed it, and see you tomorrow for a refresh on the pipes !

Nota bene

The reason why the parenthesis are working is that everything inside parentheses is in a subprocess, and the result is thus the one of the whole subprocess (the whole command, with both commands inside).

Therefore, you should not use this to pass a variable, as the subprocess is not going to affect the context of the main process !