Sinisterly
Techniques of writing scripts in Bash - Advanced - Printable Version

+- Sinisterly (https://sinister.ly)
+-- Forum: Coding (https://sinister.ly/Forum-Coding)
+--- Forum: Coding (https://sinister.ly/Forum-Coding--71)
+--- Thread: Techniques of writing scripts in Bash - Advanced (/Thread-Techniques-of-writing-scripts-in-Bash-Advanced)



Techniques of writing scripts in Bash - Advanced - unixbreak - 11-17-2012

Just published this on my personal blog > http://net-solutions.pro and i would like to share it with you as wel. Also any suggestions are welcomed (i am very interested into
this)

library file functions in this example can be downloaded HERE
test file HERE

Here's how you can speed up the work, as well as improve the reliability of scripts.

Tip 1

In the beginning of each script we'll put something like:
Code:
read-n 1 -P "Are you sure you want to run it (y / [a]):" AMSURE [ " $ AMSURE " = "y" ] | | echo "" 1 > & 2
The echo command, by the way, is necessary here because when you click <y> you will not have a line feed, therefore, next string will go to any output .

Tip 2

This is the key advice. In order to not write every time the same thing - use libraries function .
Get a library , (myfunc.sh - as example) and place it, such as / usr / bin. When writing the script, it will help to reduce your work.

Here's an example

Code:
myAskYN () { local AMSURE if [-n " $ 1 " ] ; then Read-n 1 -P " $ 1 (y / [a]): " AMSURE else Read-n 1 AMSURE Fi echo "" 1 > & 2 if [ " $ AMSURE " = " y " ] ; then return 0 else return 1 Fi }

You can write also another similar function myAskYNE, in which the return is replaced by exit. Then the record will be even easier:

Code:
myAskYN "Are you sure you want to run it?" | | exit

Advantages are obvious: a) write less code, and b) the code easier to read, and c) are not distracted by little things like boxes "(y / [a]):" the test (note that [a] means any, and climbed into the square quotes indicate that this is the default).

Finally here. In order to use the functions from the library, it should not forget to include it in the script:

Code:
myAskYN () { local AMSURE if [-n " $ 1 " ] ; then Read-n 1 -P " $ 1 (y / [a]): " AMSURE else Read-n 1 AMSURE Fi echo "" 1 > & 2 if [ " $ AMSURE " = " y " ] ; then return 0 else return 1 Fi }

Note that the name is assigned to the script. This allows you to specify the name of the script once, and therefore, you can duplicate the line and replace the name of the library to connect the other library functions, if necessary.
Now, any script that starts with these three lines never do something without asking.

Tip 3

Will develop and demonstrate the success of a few obvious features with minimal commentary.

Code:
sayWait () { local AMSURE [-N " $ 1 " ] && echo "$ @" 1 > & 2 read-n 1 -P "(press any key to continue)" AMSURE echo "" 1 > & 2 } cdAndCheck () { cd " $ 1 " if ! [ "$ (pwd)" = " $ 1 " ] ; then echo "!! I can not get to the directory $ 1 - can not continue. leave. " 1 > & 2 exit 1 fi } checkDir () { if ! [-D " $ 1 " ] ; then if [-z " $ 2 " ] ; then echo "!! No directory $ 1 - can not continue. leave. " 1 > & 2 else echo " $ 2 " 1 > & 2 Fi exit 1 fi } checkFile () { if ! [-F " $ 1 " ] ; then if [-z " $ 2 " ] ; then echo "!! No file $ 1 - can not continue. leave. " 1 > & 2 else echo " $ 2 " 1 > & 2 Fi exit 1 fi } checkParm () { if [-z " $ 1 " ] ; then echo "!! $ 2 . Unable to continue. leave. " 1 > & 2 exit 1 Fi }

It will turn your attention to the combination 1> & 2 after the echo. The fact is that your script will probably display some valuable information. Combination 1> & 2 is redirecting output to standard error. And when you call the script as follows:

My -script.sh> out.txt
My -script.sh | less


there will be no unnecessary errors and service messages, only what you really want to print.

Tip 4

In Bash is not very good things with the return of a value from the function. However, with its own library that question is easily solved. Just please create a variable in which the function will write the value, and to get out of the function that analyze this variable. By the way, variables are at the beginning of the library of your functions. Also, you can have other variables, which you can use everywhere. Here is the beginning of your library functions:

curPath = # variable with the current absolute path where the script
CRES = # variable to return the text values of the functions
pYes = # option - yes, which is discussed later


Now we can add to the collection a useful function:

Code:
input1 () { local a1 if [-n " $ 1 " ] ; then Read-P " $ 1 " -sn 1 CRES else Read sn- 1 CRES Fi # Check for valid choices while [ " $ 2 " = " $ {2 # * $ CRES} " ] ; do Read sn- 1 CRES Done echo $ CRES 1 > & 2 }

Here is an example of its use:

cat << 'EOF'
Make your choice:
------------------------
a) Step 1
b) Action 2
.) Output
EOF
input1 "Your choice:" "AB."
echo "The choice was: $ CRES "


This feature limits the keystrokes to a list of (in this case a, b, and point). No other keys will not be seen. The example also shows the use of a variable return ($ cRes). It returns the letter, pressed by the user.

Tip 5

What script with no parameters? Their processing written tons of literature. Share your vision.

1.Ideally, the parameters are treated regardless of their sequence.

2.I do not like using the single-letter options (and therefore getopts) because is kinda confusing. For a script -r means replace, for the other replicate, and for the third remove. Looks impossible. So I use the two notations, and at the same time: a)-show-files-only, b)-sfo (as a reduction from the previous).

3.The script should generate an error of unknown key. This to help identify errors in writing parameters.

4. We start from the board rule: never run the script without confirmation. But add to this the important exception - if no key-yes (key, of course, may be used).

5. Keys can be accompanied by value. In this case, the long options is generally valid:-source-file = my.txt , or -sf my.txt

In light of this treatment options might be:

Code:
; ; PDestFile = " $ 1 " elif [-z " $ 1 " ] ; then Break # Keys ended else echo "Error: unknown key" 1 > & 2 exit 1 fi shift done checkParm " $ pSourceFile " "Do not set the original file" checkParm " $ pDestFile " "Do not set output file" if [ " $ pYes " ! = "1" ] ; then myAskYNE "Are you sure you want to run it?" Fi echo "Source = $ pSourceFile , Destination = $ pDestFile "

This code provides the following features:

. / Test.sh-sf mysource-df mydest
. / Test.sh - Source-file = MySource - dest-file = mydest
. / test.sh - Source-file = MySource - dest-file = mydest - Yes


-Parameters can be specified in any order and combination of full and reduced form of keys.
-Because the parameters are required, a test verify their presence >> checkParm.
-If no key-yes, there will always prompt for confirmation.

This is a basic piece that can be further developed. For example, add a couple of functions processing parameters in our library:

Code:
procParmS () { [-Z " $ 2 " ] && return 1 if [ " $ 1 " = " $ 2 " ] ; then CRES = " $ 3 " return 0 Fi return 1 } procParmL () { [-Z " $ 1 " ] && return 1 if [ " $ {# 2} = $ 1 " , = " $ 2 " ] ; then CRES = " $ {2 # $ 1 =} " return 0 Fi return 1 }

The cycle of processing parameters will look much more better:

Code:
while [ 1 ] ; do if [ " $ 1 " = "- Yes" ] ; then pYes = 1 elif procParmS "-SF" " $ 1 " " $ 2 " ; then pSourceFile = " $ CRES " ; shift elif procParmL "- Source-file" " $ 1 " ; then pSourceFile = " $ CRES " elif procParmS "DF-" " $ 1 " " $ 2 " ; then pDestFile = " $ CRES " ; shift elif procParmL "- dest-file" " $ 1 " ; then pDestFile = " $ CRES " elif [-z " $ 1 " ] ; then Break # Keys ended else echo "Error: unknown key" 1 > & 2 exit 1 fi shift done

In fact, this cycle can be copied from the script to the script without thinking about anything, except the names of keys and a variable name for this key. And in this case, they are not repeated, and the opportunity for error.
no limit to perfection, and can be a long time "improve" functions, such as procParmS check for non-null value, and the third parameter to fall out in error in this case. And so on.

library file functions in this example can be downloaded HERE
test file HERE

Hope you'll enjoy it.


RE: Techniques of writing scripts in Bash - Advanced - jabberwock - 11-17-2012

i use
Code:
kill -SIGINT $$
instead of
Code:
exit

anyway great tutorial


RE: Techniques of writing scripts in Bash - Advanced - unixbreak - 11-17-2012

Code:
kill -SIGINT $$

sends an interrupt to the shell process (whose pid is stored in the $$ variable).

You can also use this test to determine if a bash script is being run sourced or was run as its own command:

Code:

Code:
x"${BASH_SOURCE[0]}" == x"$0"

If this is true, then it isn't sourced, if it's false (the scriptname is not $0) it was sourced.

thanks for appreciation