Tuesday, September 8, 2020

Bash scripting and shell programming linux part 3

The Part#3 includes:

  • Variable scope
  • let command
  • case statements
  • eval command
  • wildcards
  • Logger
  • Reading a file line by line
  • expr command
  • loop control statements - Break and Continue
  • Debugging

variable scope:

Global:

  • By default, variables are global.
  • define variables before use it
  • If you define a global variable in a function, it will be only be available after the function is called.
Local:
  • Can only be accessed within a function using a local keyword, example: local LOCAL_VARIABLE=1
let command:
  • The let command is an arithmetic operator. It is almost same as (( )). Only difference is that, let is an arithmetic command while (( )) is a compound command.
  • It is a built-in command which instructs shell to perform an evaluation of arithmetic expressions. No spaces should be used around the arithmetic operand with let command.

 let y=y+1
 echo $y
1
let y="34 +45"
echo $y
79

case statements:
A case construct helps us to simplify nested if statement. You can match several variables against one variable. Each case is an expression matching a certain pattern.

Syntax:
case $var in
pattern_1)
    Commands
;;
pattern_N)
    Commands
;;
esac

Example:
cat > case.sh
#!/usr/bin/bash
echo "Enter the name of the State"
read state
case $state in
"Uttar Pradesh")
echo "Capital id Lucknow"
;;
"Bihar")
echo " Capital id Patna"
;;
*)
echo " You discovered an unknown state"
;;
esac

chmod +x case.sh
./case.sh
Enter the name of the State
Bihar
 Capital id Patna
./case.sh
Enter the name of the State
bihar
 You discovered an unknown state

eval command:
The eval command is a built-in command. It takes a string as its argument and evaluate it, then run the command stored in the argument. It allows using the value of a variable as a variable.
eval echo \${$User}


cat > eval.sh
#!/usr/bin/bash
hello=Mr.x
user=hello
echo \${$user}
eval echo "\${$user}"

chmod +x eval.sh
./eval.sh
$[hello}
Mr.x

But command "eval echo \${$User}" runs the parameter passed to eval. After expansion, remaining parameters are echo and ${Hello}. Hence eval command runs the command echo ${Hello}. And so the output is Mr. X

Wild cards:
  • A character or string used for pattern matching.
  • wildcards can be used with most of the commands like cp, ls, rm etc.
* : Matches zero or more characters.
? : Matches exactly one character

Character classes[]: Matches any of the characters included between the brackets.matches exactly one character.
Example:
[aeiou]
ca[nt]* : can, cat, candy, catter etc.
Character classes [!]: Matches any of the characters not included between the brackets. matches exactly once character.
Example:
[!aeiou] : Devdas, criccket.

Ranges: use two chars separated by a hypen to create a range in a character class.
[a-g]* : matches all files starting with a,b,c,d,e,f,g
[1-5]*: matches all files started with 1,2,3,4,5

Named character class: 
[[:alpha:]]
[[:alnum:]]
[[:digit:]]
[[:lower:]]
[[:upper:]]
[[:space::]]

escape character: "\" is called escape character. use it to match a wildcard character.
Example:
*\? : match all files that end with a question mark.


Example:
 ls -l a*
-rwxr-xr-x    1 oracle   dba              22 Aug 11 03:20 a.sh

ls c[aeiou]*
case.sh    config.sh

ls c[!aeiou]*
c.sh

ls [a-d]*
a.sh       b.sh       c.sh       case.sh    config.sh

ls [[:digit:]]*
20200819mycat.jpg

ls *.txt
test.txt

ls ?est.txt
test.txt

copying all the html files from current directory to /a directory.
#!/usr/bin/bash
for FILE in *.html
do
echo "copying $FILE"
cp $FILE /a
done

Logging:
Syslog:
  • The syslog standards uses facilities and severities to categorize messages.
    • Facilities: kern,mail,user,daemon,auth,local0
    • Severities: alert, emerg,crit,err,warning,notice,info debug
  • Log files locations are configureables
    • /var/log/messages
    • /var/log/syslog
Logging with logger:
logger "Message"
logger -p local0.info "Message"
logger -t myscript -p local0.info "Message"
logger -i -t myscript -p local0.info "Message"

Reading a file line by line:
#!/usr/bin/bash
LINE_NUM=1
while read LINE
do
echo "$LINE_NUM : $LINE"
((LINE_NUM++))
done < /test/test.txt

expr command:

  • The expr command in Unix evaluates a given expression and displays its corresponding output. It is used for: Basic operations like addition, subtraction, multiplication, division, and modulus on integers.
  • Evaluating regular expressions, string operations like substring, length of strings etc.
Syntax:

$expr expression


Performing operations on variables inside a shell script

Example: Adding two numbers in a script

echo "Enter two numbers"
read x 
read y
sum=`expr $x + $y`
echo "Sum = $sum"

Note: expr is an external program used by Bourne shell. It uses expr external program with the help of backtick. The backtick(`) is actually called command substitution.

Comparing two expressions
Example:
x=10
y=20
# matching numbers with '='
res=`expr $x = $y`
echo $res

# displays 1 when arg1 is less than arg2
res=`expr $x \< $y`
echo $res

# display 1 when arg1 is not equal to arg2
res=`expr $x \!= $y`
echo $res

For String operations
Example: Finding length of a string
x=geeks
len=`expr length $x`
echo $len

Example: Finding substring of a string
x=geeks
sub=`expr substr $x 2 3` 
#extract 3 characters starting from index 2
echo $sub

Break Statement:
The break statement is used to terminate the execution of the entire loop, after completing the execution of all of the lines of code up to the break statement. It then steps down to the code following the end of the loop.

Syntax:
The following break statement is used to come out of a loop −
break

The break command can also be used to exit from a nested loop using this format −
break n
Here n specifies the nth enclosing loop to the exit from.

Example 1:
Here is a simple example which shows that loop terminates as soon as a becomes 5 −

#!/usr/bin/bash
a=0
while [ $a -lt 10 ]
do
echo "$a"
if [ $a -eq 5 ]
then 
break
fi
a=`expr $a + 1`
done

Upon execution, you will receive the following result −
0
1
2
3
4
5
Example 2 of nested for loop. This script breaks out of both loops if var1 equals 2 and var2 equals 0 −

#!/usr/bin/sh
for var1 in 1 2 3
do
   for var2 in 0 5
   do
      if [ $var1 -eq 2 -a $var2 -eq 0 ]
      then
         break 2
      else
         echo "$var1 $var2"
      fi
   done
done

Upon execution, you will receive the following result. In the inner loop, you have a break command with the argument 2. This indicates that if a condition is met you should break out of outer loop and ultimately from the inner loop as well.

1 0
1 5

The continue statement:
The continue statement is similar to the break command, except that it causes the current iteration of the loop to exit, rather than the entire loop.

This statement is useful when an error has occurred but you want to try to execute the next iteration of the loop.

Syntax
continue
Like with the break statement, an integer argument can be given to the continue command to skip commands from nested loops.

continue n
Here n specifies the nth enclosing loop to continue from.

Example 1:
The following loop makes use of the continue statement which returns from the continue statement and starts processing the next statement −

#!/bin/sh
NUMS="1 2 3 4 5 6 7"
for NUM in $NUMS
do
   Q=`expr $NUM % 2`
   if [ $Q -eq 0 ]
   then
      echo "Number is an even number!!"
      continue
   fi
   echo "Found odd number"
done

Upon execution, you will receive the following result −
Found odd number
Number is an even number!!
Found odd number
Number is an even number!!
Found odd number
Number is an even number!!
Found odd number

Debugging:
Debugging is required to fix bugs or errors and to determine the root of unexpected behavior.

Technique 1:
cat >debug.sh
#!/usr/bin/bash -x
VAR_TEST="test"
echo "$VAR_TEST"

chmod +x debug.sh
 ./debug.sh

Output:
+ VAR_TEST=test
+ echo test
test

Technique 2:
#!/usr/bin/bash
VAR_TEST="test"
set -x
echo $VAR_TEST
set +x
hostname

output:
+echo test
linuxTestServ

-e option:
  • Exit on error
  • can be used with other options
    • #!/usr/bin/bash -ex
    • #!/usr/bin/bash -xe
    • #!/usr/bin/bash -e -x
    • #!/usr/bin/bash -x -e
Example 1:
#!/usr/bin/bash -e
FILE_NAME="/invalid"
ls $FILE_NAME
echo $FILE_NAME

Output:
ls: 0653-341 The file /invalid does not exist.
/invalid

Example 2:
#!/usr/bin/bash -ex
FILE_NAME="/invalid"
ls $FILE_NAME
echo $FILE_NAME

Output:
+ FILE_NAME=/invalid
+ ls /invalid
ls: 0653-341 The file /invalid does not exist.

-v option: Prints shell input lines as they are read.
#!/usr/bin/bash -v
VAR_TEST="test"
echo "$VAR_TEST"

Output:
#!/usr/bin/bash -v
VAR_TEST="test"
echo "$VAR_TEST"
test

#!/usr/bin/bash -vx
VAR_TEST="test"
echo "$VAR_TEST"

Output:
#!/usr/bin/bash -vx
VAR_TEST="test"
+ VAR_TEST="test"
echo "$VAR_TEST"
+ echo test
test

PS4:
  • Controls what is displayed before a line when using teh "-x" option.
  • the default value is "+"
  • Bash variables BASH_SOURCE, LINENO etc.
Example:
cat > ps4.sh
#!/usr/bin/bash -x
PS4='+ $BASH_SOURCE : $LINENO : '
TEST_VAR="test"
echo "$TEST_VAR"

chmod +x ps4.sh
./ps4.sh
+ PS4='+ $BASH_SOURCE " $LINENO " '
+ ./ps4.sh : 3 : TEST_VAR=test
+ ./ps4.sh : 4 : echo test
test

#!/usr/bin/bash -x
PS4='+ $BASH_SOURCE : $LINENO : $FUNCNAME[0]()'
debug(){
echo "Executing: $@"
$@
}
debug ls


+ PS4='+ $BASH_SOURCE : $LINENO : $FUNCNAME[0]()'
+ ./ps41.sh : 7 : [0]()debug ls
+ ./ps41.sh : 4 : debug[0]()echo 'Executing: ls'
Executing: ls
+ ./ps41.sh : 5 : debug[0]()ls
20200819mycat.jpg 


DOS VS Linux  file types:
A file can contain CRLF/Carriage return, Line feed. So when we are moving file from DOS system to Linux, we should use " dos2unix script.sh " command to make it compatible with BASH executable.

To continue, go to the next page, bash-scripting-and-shell-programming-part4.

No comments:

Post a Comment

Featured Post

11g to 12c OSB projects migration points

1. Export 11g OSB code and import in 12c Jdeveloper. Steps to import OSB project in Jdeveloper:   File⇾Import⇾Service Bus Resources⇾ Se...