Showing posts with label Shell Script. Show all posts
Showing posts with label Shell Script. Show all posts

Sunday, 27 April 2014

Shell - For Loop

A 'for loop' is a bash programming language statement which allows code to be repeatedly executed.  For example, you can run UNIX command or task 5 times or read and process list of files using a for loop.

Bash by default support three types of loops 
for loop, while loopuntil loop.

for variable in [list]; do 
          action item
 done

 OR

for variable in [list]
do
  action item
done

argument ---- any variable that we set

argument is equal to the first element or each element in the list as it cycles through the list. It assigns value to the argument.

Exam:

1. 
for contries in INDIA JAPAN MALI
   do
       echo $contries
   done

2.
for VARIABLE in 1 2 3 4 5 .. N
do
command1
command2
commandN
done

OR

3.
for VARIABLE in file1 file2 file3
do
command1 on $VARIABLE
command2
commandN
done

OR

4.
for OUTPUT in $(Linux-Or-Unix-Command-Here)
do
command1 on $OUTPUT
command2 on $OUTPUT
commandN

done

For printing numbers from 1 to 100

Latest bash version 3.0+ has inbuilt support for setting up ranges.  The following example illustrates the use of "ranges" in a for-loop.

for i in {1..10}
do
echo "$i"

done

The expression "{1..10}" is a shorthand for the list "1 2 3 4 5 6 7 8 9 10". 


Bash v4.0+ has inbuilt support for setting up a step value using {START..END..INCREMENT} 


#!/bin/bash
echo "Bash version ${BASH_VERSION}..."
for i in {0..10..2}
  do
     echo "Welcome $i times"
 done
Following is the example to display all the files starting with .bash and available in your home.

#!/bin/sh

for FILE in $HOME/.bash*
do
   echo $FILE
done
This will produce following result:
/root/.bash_history
/root/.bash_logout
/root/.bash_profile
/root/.bashrc

The for statement is used when you want to loop through a list of items. The body of the loop is put between do and done. Let's say that we want to write a program that will validate numbers in a given list. These numbers can be loaded from a file, hard coded, or manually entered by the user. For our example, we will ask the user for a list of numbers separated with spaces. We will validate each number and make sure that it is between 1 and 100. The best way to write a program like this would be to use a for loop. 

#!/bin/sh
# Validate numbers...

echo "Please enter a list of numbers between 1 and 100. "
read NUMBERS

for NUM in $NUMBERS
do
 if [ "$NUM" -lt 1 ] || [ "$NUM" -gt 100 ]; then
  echo "Invalid Number ($NUM) - Must be between 1 and 100!"
 else
  echo "$NUM is valid."
 fi
done

In some cases it is more suitable to use a while-loop instead of a for-loop. The following example does essentially the same the for-loop above:


#!/bin/bash
count=1
while [[ $count -le 9 ]]
do
    echo "$count"
    (( count++ ))
done

-------------------------------------------------------

[carol@octarine ~/html] cat html2php.sh

#!/bin/bash
# specific conversion script for my html files to php
LIST="$(ls *.html)"
for i in "$LIST"; do
     NEWNAME=$(ls "$i" | sed -e 's/html/php/')
     cat beginfile > "$NEWNAME"
     cat "$i" | sed -e '1,25d' | tac | sed -e '1,21d'| tac >> "$NEWNAME"
     cat endfile >> "$NEWNAME"
done

---------------------------------------------------------------

 Using Arguments

Example 10. Shell Script Arguments

#!/bin/bash
# example of using arguments to a script
echo "My first name is $1"
echo "My surname is $2"
echo "Total number of arguments is $#" 

----------------- ---------------- --------------- -------------
echo "$0 counts the lines of code" 
l=0
n=0
s=0
for f in $*
do
l=`wc -l $f | sed 's/^\([0-9]*\).*$/\1/'`
echo "$f: $l"
        n=$[ $n + 1 ]
        s=$[ $s + $l ]
done

   Index Of Commands

--> for a in $@ Every input

--> $1, $2, ... First input, second input, ... $0 Name of script (command you typed to run it.) $# Number of inputs

--> $@ All inputs (1-end) with a space between $? Return value of last command (tricky to use.)

--> # Comment. Must be first thing in line

--> $abc Look up value of abc variable

--> $(abc) Run command "abc". $($abc) looks up abc and runs it.

--> ${abc} {}'s are optional parenthesis. They are needed for parms past 9 (${10}).

--> [ ] Short cut for test

--> ${1:3} Substring of $1, starting at 3rd position. ${abc:2:4} Substring of abc, starting at 2nd position and using next 4 characters.


--> "read a" Read one line from keyboard and put in variable a

--> 'abc' (quotes near ENTER): Treat this as a bunch of letters.

--> "abc" (double quotes): Expend all $-rules, but otherwise treat as a bunch of letters.

--> `abc` (back-tic [upper-left]): same as $(abc). Runs command. eval abc: Evaluate. Also same as $(abc).

-------------------- -------------------       ---------------------------------

for a in 4 8 3 7 13 4
do
  echo -n $a"  "
  if test $a -ge 5
  then
    echo "big"
  else
    echo "small"
  fi
done

---------------------------------------- ------------------------------------- ------------------------------

if [ $# -ne 1 -o ! -f $1 ]
then
  echo "Usage: $0 FILENAME"
  exit 1
fi

words=0
for a in $(cat $1)
do
#  echo "["$a"]"
words=$((1+$words))
done

echo "Num of words is" $words

$(cat $1) simply "pastes" that file after for a in, which then looks at every word. 
Note the output of cat is automatically redirected (it does not go to the screen.) words is a standard counter, with one added for each word, in the awkward script manner. If you have a lot of math, use a more formal programming language.

The first part is a standard check: if there is not one input, or it is not a file (-o (letter O) is or, ! is not -- see %info test).
------------------------------------- ------------------------------- ----------------

  Three-expression bash for loops syntax

It is characterized by a three-parameter loop control expression; 
consisting of an initializer (EXP1), a loop-test or condition (EXP2), and a counting expression (EXP3). 

for (( EXP1; EXP2; EXP3 ))
do
command1
command2
command3
done

#!/bin/bash
for (( c=1; c<=5; c++ ))
do
   echo "Welcome $c times"
done

-------------  ----------------------- --------------

$ cat for4.sh
i=1
for username in `awk -F: '{print $1}' /etc/passwd`
do
 echo "Username $((i++)) : $username"
done

$ ./for4.sh
Username 1 : ramesh
Username 2 : john
Username 3 : preeti
Username 4 : jason
----------------------------- --------------------------- ----------- 

  Loop through files and directories in a for loop

To loop through files and directories under a specific directory, just cd to that directory, and give * in the for loop as shown below.

The following example will loop through all the files and directories under your home directory.

$ cat for5.sh
i=1
cd ~
for item in *
do
 echo "Item $((i++)) : $item"
done

$ ./for5.sh
Item 1 : positional-parameters.sh
Item 2 : backup.sh
Item 3 : emp-report.awk
Item 4 : item-list.sed
Item 5 : employee.db
Item 8 : storage
Item 9 : downloads
Usage of * in the bash for loop is similar to the file globbing that we use in the linux command line when we use ls command (and other commands).

For example, the following will display all the files and directories under your home directory. This is the concept that is used in the above for5.sh example.

cd ~
ls *

Monday, 31 March 2014

Bash File Testing

-b filenameBlock special file
-c filenameSpecial character file
-d directorynameCheck for directory existence
-e filenameCheck for file existence
-f filenameCheck for regular file existence not a directory
-G filenameCheck if file exists and is owned by effective group ID.
-g filenametrue if file exists and is set-group-id.
-k filenameSticky bit
-L filenameSymbolic link
-O filenameTrue if file exists and is owned by the effective user id.
-r filenameCheck if file is a readable
-S filenameCheck if file is socket
-s filenameCheck if file is nonzero size
-u filenameCheck if file set-ser-id bit is set
-w filenameCheck if file is writable
-x filenameCheck if file is executable

#!/bin/bash

 file="./file"

if [ -e $file ]; then

echo "File exists"
else 

echo "File does not exists"
fi 

Similarly for example we can use while loop to check if file does not exists. This script will sleep until file does exists. Note bash negator "!" which negates the -e option.

#!/bin/bash
 
while [ ! -e myfile ]; do

# Sleep until file does exists/is created

sleep 1

done

conditional statements if...then if...then...else

We can check the conditional statement in bash scripting

1. if..then..fi statement (Simple If)

2. if..then..else..fi statement (If-Else)

3. if..elif..else..fi statement (Else If ladder)

4. if..then..else..if..then..fi..fi..(Nested if)

File Operations


-s    file exists and is not empty
-f    file exists and is not a directory
-d    directory exists
-x    file is executable
-w    file is writable
-r    file is readable


Numeric Comparison


expr1 -eq expr2   Returns true if the expressions are equal
expr1 -ne expr2   true if the expressions are not equal
expr1 -gt expr2   true if expr1 is greater than expr2
expr1 -ge expr2   Returns true if expr1 >= to expr2
expr1 -lt expr2   Returns true if expr1 is less than expr2
expr1 -le expr2   Returns true if expr1 is >= expr2
! expr1    Negates the result of the expression


-lt<
-gt>
-le<=
-ge>=
-eq==
-ne!=

String Comparison

Str1 = Str2    Returns true if the strings are equal
Str1 != Str2   Returns true if the strings are not equal
-n Str1        Returns true if the string is not null
-z Str1        Returns true if the string is null


=equal
!=not equal
<less then
>greater then
-n s1string s1 is not empty
-z s1string s1 is empty


if..then..fi

if [ expression ]
then
   Statement(s) to be executed if expression is true
fi


Here Shell expression is evaluated. If the resulting value is true, given statement(s) are executed.If expression is false then no statement would be not executed. Most of the times you will use comparison operators while making decisions.

#!/bin/sh
a=10
b=20
if [ $a == $b ]
then
   echo "$a is equal to $b"
fi

if [ $a != $b ]
then
   echo "a is not equal to b"
fi


#!/bin/bash
count=100
if [ $count -eq 100 ]
then
  echo "Count is 100"
fi


#!/bin/bash
if [ $? -eq 0 ]
then
echo 'Success!'

  else
echo "Failed!!!!"
fi


#!/bin/bash
count=`wc -l /root/nopass | cut -f1 -d" "`

echo $count
if [ "$count" > "150" ]
then
echo "File has more than 150 lines"
fi


#!/bin/bash
gender="female"
if [[ "$gender" == f* ]] #syntax differ when * comes
then
echo "Welcome, Madame.";
fi


#!/bin/bash
if [ "$(whoami)" != 'root' ]; then
   echo "You have no permission to run $0 as non-root user."
    exit 1;
fi


Note: you can give the system commands in two ways: 
        1. inside tilde `` Or using second method
        2. $()

if..then..else..fi

; semi-colon is a command terminator in bash

Use single quote when you want to literally print everything inside the single quote.
echo 'Hostname=$HOSTNAME ;  Current User=`whoami` ; Message=\$ is USD'

Use double quotes when you want to display the real meaning of special variables.
echo "Hostname=$HOSTNAME ;  Current User=`whoami` ; Message=\$ is USD"

Double quotes will remove the special meaning of all characters except the following:

$ Parameter Substitution.
` Backquotes
\$ Literal Dollar Sign.
\´ Literal Backquote.
\” Embedded Doublequote.
\\ Embedded Backslashes.

Before special variables use escape characters

#!/bin/sh
# This is some secure program that uses security.

VALID_PASSWORD="secret" #this is our password.

echo -n "Please enter the password:"
read PASSWORD

if [ "$PASSWORD" == "$VALID_PASSWORD" ]; then
        echo "You have access!"
else
        echo "ACCESS DENIED!"
fi

If..then..else if..then..else if..then..else [Nested if]


#!/bin/sh

# Prompt for a user name...
echo -n "Please enter your name:"
read USERNAME

# Check for the file.
if [ -s ${USERNAME}_DAT ]; then
        # Read the age from the file.
        AGE=`cat ${USERNAME}_DAT` # This is how you execute a command and put                                                # the text output from the command into a                                                    # variable.
        echo "You are $AGE years old!"
else
        # Ask the user for his/her age
        echo "How old are you?"
        read AGE

 if [ "$AGE" -le 2 ]; then
  echo "You are too young!"
 else
  if [ "$AGE" -ge 100 ]; then
   echo "You are too old!"
  else
          # Write the age to a new file.
          echo $AGE > ${USERNAME}_DAT
         fi
        fi
fi


If..elif (else if) 

if [ expression 1 ]
then
   Statement(s) to be executed if expression 1 is true
elif [ expression 2 ]
then
   Statement(s) to be executed if expression 2 is true
elif [ expression 3 ]
then
   Statement(s) to be executed if expression 3 is true
else
   Statement(s) to be executed if no expression is true
fi


#!/bin/sh

a=10
b=20

if [ $a == $b ]
then
   echo "a is equal to b"
elif [ $a -gt $b ]
then
   echo "a is greater than b"
elif [ $a -lt $b ]
then
   echo "a is less than b"
else
   echo "None of the condition met"
fi


#!/bin/sh

# Prompt for a user name...
echo "Please enter your age:"
read AGE

if [ "$AGE" -lt 20 ] || [ "$AGE" -ge 50 ]; then
 echo "Sorry, you are out of the age range."
elif [ "$AGE" -ge 20 ] && [ "$AGE" -lt 30 ]; then
 echo "You are in your 20s"
elif [ "$AGE" -ge 30 ] && [ "$AGE" -lt 40 ]; then
 echo "You are in your 30s"
elif 
\[ "$AGE" -ge 40 ] && [ "$AGE" -lt 50 ]; then
 echo "You are in your 40s"
fi


 Nested if/else


#!/bin/bash

# Declare variable choice and assign value 4
choice=4

# Print to stdout
 echo "1. Bash"
 echo "2. Scripting"
 echo "3. Tutorial"
 echo -n "Please choose a word [1,2 or 3]? "

# Loop while the variable choice is equal 4
# bash while loop

while [ $choice -eq 4 ]; do

# read user input
read choice

# bash nested if/else
if [ $choice -eq 1 ] ; then

        echo "You have chosen word: Bash"

else

        if [ $choice -eq 2 ] ; then
                 echo "You have chosen word: Scripting"
        else

                if [ $choice -eq 3 ] ; then
                        echo "You have chosen word: Tutorial"
                else
                        echo "Please make a choice between 1-3 !"
                        echo "1. Bash"
                        echo "2. Scripting"
                        echo "3. Tutorial"
                        echo -n "Please choose a word [1,2 or 3]? "
                        choice=4
                fi
        fi
fi

done

********************************************

Exmp1:

#!/bin/bash
# Author: 

# Date: 
# Purpose: 

password="IF"
echo -n "Please enter your password:"
read passwd

if [ $password = $passwd ]; then
 echo "You have the access to run this script"
else
 echo "Access Denied"
exit
fi

if [ -d ~/IF ]; then
echo "Directory exists. creting file"
 cd /home/ec2-user/IF ; touch iftesting
else
 echo "directory does not exists...Creating directory"
  mkdir /home/ec2-user/IF
exit
fi



Exmp2:

#!/bin/sh

# Prompt for a user name... 
 
echo "Please enter your name:"
read USERNAME

# Check for the file.
 
if [ -s ${USERNAME}_DAT ]; then
        # Read the age from the file.
        AGE=`cat ${USERNAME}_DAT`
        echo "You are $AGE years old!"
else
        # Ask the user for his/her age
        echo "How old are you?"
        read AGE

 if [ "$AGE" -le 2 ]; then
  echo "You are too young!"
 else
  if [ "$AGE" -ge 100 ]; then
   echo "You are too old!"
  else
          # Write the age to a new file.
          echo $AGE > ${USERNAME}_DAT
         fi
        fi
fi

Exmp3:


#!/bin/sh
# Prompt for a user name... 
 
echo "Please enter your age:"
read AGE

if [ "$AGE" -lt 20 ] || [ "$AGE" -ge 50 ]; then
 echo "Sorry, you are out of the age range."
 
elif [ "$AGE" -ge 20 ] && [ "$AGE" -lt 30 ]; then
 echo "You are in your 20s"
 
elif [ "$AGE" -ge 30 ] && [ "$AGE" -lt 40 ]; then
 echo "You are in your 30s"
 
elif [ "$AGE" -ge 40 ] && [ "$AGE" -lt 50 ]; then
 echo "You are in your 40s"
fi
 
Exmp4:
 
#!/bin/bash
# Purpose: Detecting Hardware Errors
# Author: 
# Note : The script must run as a cron-job.
# Last updated on : 
# -----------------------------------------------
 
# Store path to commands
LOGGER=/usr/bin/logger
FILE=/var/log/mcelog
 
# Store email settings
AEMAIL="jeffinm@gmail.com "
ASUB="H/W Error - $(hostname)"
AMESS="Warning - Hardware errors found on $(hostname) @ $(date). See log file for the details /var/log/mcelog."
OK_MESS="OK: NO Hardware Error Found."
WARN_MESS="ERROR: Hardware Error Found."
 
 
# Check if $FILE exists or not
if test ! -f "$FILE" 
then   
 echo "Error - $FILE not found or mcelog is not configured for 64 bit Linux systems."
 exit 1
fi
 
# okay search for errors in file
error_log=$(grep -c -i "hardware error" $FILE)
 
# error found or not?
if [ $error_log -gt 0 ]
then    # yes error(s) found, let send an email
 echo "$AMESS" | email -s "$ASUB" $AEMAIL
else    # naa, everything looks okay
 echo "$OK_MESS"
fi