Linux Bash Scripting Tutorial


Variables

Variable is given a name it to a memory location. Variable has a value and zero or more attributes. variables can be aasigned with numbers or strings or special characters in shell. variables are nothing but shell variables or user defined variables in shell

Bash variables can be

  • typed
  • untyped

Through variables, you can store and manipulate information, a fundamental aspect of pro- gramming.

Declaring variables in Bash shell Syntax

	       untyped variable
		variable=[value]   #untyped variables
		
		typed variable
		declare -i   i=100 #typed variable of integer
		declare -r   k=100 #readonly variable, must be intialized
		declare -a   aa; #array variable

	

There are 3 different types of parameters:

  • Shell Variables
  • Special Parameters
  • Positional Parameters

Untyped variables

Untyped variable values considered as string literal. No prior declarion required for untyped variables

Setting value to a untyped variable
variable=[value]

*optional [value] is set , value stored in variable. if not set null will be assigned to variable.

for ex:    
		x=10  ;        //Number 10 assigned to variable x
		name="sam" ;  //String sam  assigned to variable name
		pwd=~;        //special character tilde~ assigned to variable pwd.
		p=           //null value assigned to variable p
		y=10+10;     // 10+10  treated as a string .

		z = 100;     // error, here bash considers z is a command and parameters are = and 100. 
			     // No space should be given before and after equal sign.
		
		

Typed variables

Prior declaration is required for typed variables using declare command

declare syntax
		declare [options]  [name[=value]]

declare -i  x=10;    // here x is declared as integer variable.
declare -i  x=10+10; // Right Hand side(RHS) treated as arithmetic expression. value of x evaluated to 20.

//declaring multiple variables
declare -i  x=20 y=20
declare -i  x=20 y=20 z=x+y  //here z has sum of x and y 

	
declare command options
OptionsDescription
-ieach variable is integer,in an assigment,,the value is evaluated as arithmetic expression
-Adeclaring associate arrays
-adeclaring indexed array
-rMarking variables as readonly, readonly variables should be assigned at the declarion
-xMark variables exported into sub shells/processes.
-fEach name is function.

Accessing variable value

Variable values can be accessed in 2 different ways

  • $ sign should be prepended before variable name $variable
    for ex:   x=10
    echo $x   //displays value x.
    					
  • $ sign with-in curly braces variable name ${variable}
    for ex:   x=10
     echo ${x}   //displays value x.
    
    This is prefered way for displaying array elements
    
    $ ~>  echo ${a[@]}  #here a is array variable
    					
** Same rule applies to both shell variables and user defined variables

ReadOnly variables

$ ~> declare -r PI=3.14159

$ ~> PI=2.789

bash: PI: readonly variable

$ ~> unset PI;

bash: unset: PI: cannot unset: readonly variable

readonly variables once set,programmer cannot unset or assign a new value. Scope of the read only variable will be from where it is declared to end of the file.

Indirect look-up


Bash allows indirect look-up using prefix ! operator

That is, ${!var} behaves like a ${${var}}

   

name=age
age=42

echo ${!name}     #prints 42

age=(10 20 30 40 50 60 70)
agelimit=age[1]

echo ${!char}   #prints 20

Unsetting variable value

Variable value can be unset using unset command



x=100
name="samuel"
echo $x, $name //displays 100,samuel


unset x
unset name
echo $x, $name //displays only comma(,), both variables set to null


Unsetting multiple variables

unset x name // removes x and name values and assigns them with null value.


Removing all Array Elements


$ ~> a=(1 2 3 4 5 6) //set values for array variable a
$ ~> echo ${a[*]} //Displays array values
1 2 3 4 5 6

$ ~> unset a //removes all values from array a
$ ~> echo ${a[*]} // array a set to null


Shell Parameter and Variable Expansion


     The "$" parameter introduces shell parameter expansion. "$" followed by variable name,performs variable expansion.



			$ ~>i=10
			$ ~>echo $i

			#here echo command does parameter expansion , before displaying output on console.

			10
		
			$ ~> name="sam"
			$ ~> echo $name     #parameter "name" expanded first , then result will be displayed on screen.

			#if u want to append some text to variable, for ex: "name" variable append "firtsname"
			$ ~> echo $namefirstname 	#display empty string or set to null, 
							#because its looking for variable called namefirstname,
							#that's not defined,anywhere in the program.

			#To solve this  $ with curly braces with variable name in it.

				${Variable}  i.e  ${name}firstname
				#displays   "samfirstname"	
			#insert some space between name and firstname string

				${name}' 'firstname
				sam firstname

		

Parameter Expansion in double Quotes,Single Quotes and Back Quotes

			$ ~> i=10
			$ ~> echo "${i}"     Double quotes does parameter expansion
			
			     10

			$ ~> echo '${i}'      Single quotes does not expand parameter
			
			     ${i}

			$ ~> cmd=ls;           Back quotes does parameter expansion
			$ ~> echo `${cmd}`

			#variable cmd set to "ls" command
			#back quotes does command substitution.
			#echo command first performs variable substitution, then back quotes expands command.
			#list of files in the current directory will be displayed.
		
${parameter:pos}

      Displays string from specified position

	var="Hello This is text message"
echo ${var3:5}
This is text message
Note:pos can start from 0, 0 means entire string.It can even be negative values, -1 means last character
echo ${var3: -7} ;gets last 7 characters,i.e reading from right to left.
message Note:There should be space between colon and number for -ve values

${parameter:pos:length}

      Extracts substring from string, pos is starting index, length is pos+length

var="Hello you got text message"
echo ${var:10:8}
got text ;  here 10th position has character 'g' from there to next 8 characters including 'g' . i.e "got text"
		
${#parameter}

      Finds length of the variable

			var="samsung"
			echo ${#var}
			7
		
${parameter:-value}

      Use parameter value if it is set otherwise use "value"

;first case var1 set to null.

var1=

echo ${var1:-"World"} ;  displays "world"
World

//second case var2 is set
var2="hello"
echo ${var2:-"World"}  //variable value will be displayed ,ignores value "world"
hello
		
${parameter:+value}

      use value if var is set, otherwise do nothing

var="Hello you got text message"
echo ${var:+"nothing"}  ; uses value i.e "nothing" because var is set, this is quite opposite to ${var:-value}
nothing
${parameter:=value}

      Use variable if it set, if it is not set display value and then assign value to variable

;first case var1 set to null.

var1=

echo ${var1:="World"} ;  displays "world"
World
echo ${var1}  ; var1 is has value "World"
World

//second case var2 is set
var2="hello"
echo ${var2:="World"}  //variable value will be displayed ,ignores value "world"
hello
${parameter:?value}

      Use var if set; otherwise, print value and exit (if not interactive). If value isn’t supplied, print the phrase parameter null or not set to stderr.

${parameter%pattern}

      Removes shortest matching piece from Right

			$ v='abc.def.ghi.klmn'
			
			# '.klmn' shortest matching piece  from right
			
			$ echo ${v%.*}
			abc.def.ghi
		
		
${parameter%%pattern}

      Removes longest matching piece from Right

			$ v='abc.def.ghi.klmn'
			
			# '.def.ghi.klmn' longest matching piece  from right
			
			$ echo ${v%.*}
			abc
		
		
${parameter#pattern}

      Removes shortest matching piece. Use the value of parameter after removing text matching pattern from the left

			$ v='abc.def.ghi.klmn'
			
			# 'abc.' shortest matching piece  from left
			
			$ echo ${v#*.}
			def.ghi.klmn
		
${parameter##pattern}

      Removes longest matching piece.

			$ v='abc.def.ghi.klmn'
			
			# 'abc.def.ghi.' longest matching piece 
			$ echo ${v##*.}
			klmn
		
		
${parameter/pat/repl}

      Finds a given pattern and replaces with 'repl' string. if pattern not found unalters the text

			example:1
			$->s='you got a phone call'
			$->echo ${s/got/received}
			you received a phone call.
			In the above example 'got' is a pattern being replaced by 'received'
			
			example 2:
			
			$->var="numbers are 1 2 3 4 5 6"
			$->echo ${var/numbers are/}
			1 2 3 4 5 6
			Pattern:numbers are 
			Replacement Text: is empty;
			The above example replaces 'numbers are' pattern with empty text.
			
		
${parameter/pat}, ${parameter//pat}

      Removes given pattern in a variable.

${parameter/pat} # removes first occurance of pattern in the parameter(left to right).
				$ 
				
				$ v=100_100_100_100
				
				$ echo {v/_}        #remove first occurance of the underscore(_) symbol from variable v
				100100_100_100
			
${parameter//pat} # removes all occurance of pattern in the parameter(left to right).
				$ 
				
				$ v=100_100_100_100
				
				$ echo {v/_}        #remove all occurance of the underscore(_) symbol from variable v
				100100100100
			
${parameter//pat/repl}

      Finds and replace the pattern.

Following example finds the all space character replaces with Underscore character,As shown below

			$ amex='3712 345678 95006'
			$
			$ echo ${amex// /_}
			3712_345678_95006
		
${parameter/#pat/repl}

      Finds pattern and replaces till it reaches last character in the pattern(left to right)

mask off credit card number: it looks for last space character. pattern: '* ' means it skips all characters until it reaches last space character, replaced with given replacement text/character(s).
		
		$ echo $amex
		
		3712 345678 95006

		$ echo ${amex/#* /***********}
		
		***********95006

		
${parameter/%pat/repl}

      Finds pattern and replaces till it reaches first character in the pattern(right to left)

mask off credit card number: it looks for first space character(right to left). pattern: ' [0-9]*' means it skips all characters until it reaches first space character, replaced with given replacement text/character(s).

		$ echo $amex
		
		3712 345678 95006
		
		echo ${amex/% [0-9]*/********************}
		
		3712********************

		
${!parameter}

      Indirect reference to variable 'paramater' , This is equal to ${${parameter}}

$ v='country'
$country='INDA'
			
#variable v  contains another variable country, ${!v} displays value of 
referenced variable, instead of original variable's value
			
$echo ${!v}
INDIA
		

Exporting variables

Exporting a variable can be done in 2 ways

  • using export command
  • using declare -x command

Variable exported using any of the above commands will be visible to all sub-shells,otherwise variable is undefined,set to null value

		$ ~>  export x=10;
		$ ~>  declare -x x=10;
	
**variables exported using export and declare -x commands will be available to all script files.

export variable example:

		$ ~> export x=10
		$ ~> y=20
		$ ~> cat exp.sh
			echo "x value:$x,y value:$y"
		$ ~> ./exp.sh
		
	

output: x value:20,y value:
y value is null, y is not visible to subshells

Built-in Shell Variables

Shell treats several paramters specially. These are read-only paratemeters. Values set by bash shell , user canot modify these variables.

Special Bash Variables
CharacterDescription
$*All Arguments of the command-line. "$*" All arguments are quoted as "$1 $2 ...${10}" based Internal Field Seperator(IFS),IFS default set to space character
$@All Arguments of the command-line. "$@" arguments are individually quoted "$1","$2"..."${10}"
$#Number of positional parameters or command line arguments
$?exit status of the most recently executed foreground pipeline.
$-Flags passed to the script(using set)
$$Process ID of the shell
$!Process Number of the last background command
$0Displays Shell Script name or command
$_Has Pathname of the script.Later stores last argument of the previous command.

$$ parameter example

Displaying process id using $$ special parameter.


$ ~> echo $$ #displays current shells process id.
calling $$ in script files will display different process id,beacuse each script file runs in sub-shell,unless specified source command.

$0 parameter example

$0 parameter displays shell script name or command.
displays shell name

			$~> echo $0
			bash
		
with in the script example.sh
		#!/usr/bash
		
		echo   $0
		echo   `basename $0`
		
./example.sh
example.sh

$# parameter example

Displays number of arguments passed to script file

for ex: script.sh 1 2 3 4 5 6
			echo "Number of arguments passed: $#"
		
output will be "Number of arguments passed: 6

In case number of arguments are fixed, $# helps us to force for required arguments
for ex: weather.sh requires city only
if [[ $# -ne 1 ]] ; then
         echo "Number of arguments must be 1";
         exit 1;
fi

		
Executing Script file
		$ ~> ./weather.sh
			or
		$ ~> ./weather.sh 19.99 NY
		
if number of arguments are 0 or more than 1 ,displays message "Number of arguments must be 1"; and exits from script execution

$* or $@ parameter example

     All arguments in the command-line "$1,$2,$3...$N"

"$*" All Arguments in the command-line are treated as one string. "$1,$2..$N".The values are seperated by first character in the $IFS,internal field seperator

"$@" All Arguments in the command-line,are individually-Quoted "$1","$2".."$N"

$? parameter example

exit status of the most recently executed foreground pipeline.

for ex:
			$ ~>  ls # ls command displays list of files and directories.
			$ ~>  echo $? # displays 0
			0 means command execution is successful otherwise failed
		

$- parameter example

    Flags passed to the script(using set)

		$ set 'uname -a' 'ls' 'pwd'
		
		$ echo $-
		pwd
		
		#last command/value assigned to $-  
	

$! parameter example

       Process number of the last background command. for ex running gedit text editor in the background.

running gedit process in the background (append ambersand symbol & ) at the end.
$~>gedit&

then issue echo $! displays process number of the last background job (here gedit)

$_ parameter example

     Initially it has script name, later stores last argument of the previous command

		$ echo
		$
		$echo $_
		echo     
		# last command without arguments
		
		2nd example: find *.sh files in the current directory,, $_ has last file in the list
		
		$ ls *.sh
		  1.sh
		  2.sh
		  3.sh
		  
		$ echo $_
		 3.sh
		 
		#Find .sh  files in the current directory and its sub-directories
		
		$ find . -iname '*.sh' -exec ls {} \;
		
		$ echo $_
		;
		#last command argument  is ;
	

Local and Global Variables

    

Variables declared within the function is called as local variables, Accessing a local variable outside function body is an error

Variables declared outside the function and within the bash script is called as Global variables

Please refer Functions Section , for Local and Global Variables usage

Prompting Variables

      Bash has 4 prompting variables PS1,PS2,PS3 and PS4

PS2 is called as secondary prompt string. its default value is >

PS1

     Primary Prompt String(PS1),

			
			

The set command

      The set command serves 2 purposes: one is to set various shell options, second one is to reassign positional parameters $1,$2,$3...

Executing set command ,gives set of variables that exists in the current environment, local or exported.

		$~> set
		BASH=/usr/bin/bash
			BASHOPTS=checkwinsize:cmdhist:complete_fullquote:expand_aliases:extglob:extquote:force_fignore:
		globasciiranges:histappend:interactive_comments:progcomp:promptvars:source
		path
		BASHRCSOURCED=Y
		BASH_ALIASES=()
		BASH_ARGC=([0]="0")
		BASH_ARGV=()
		BASH_CMDS=()
		BASH_COMPLETION_VERSINFO=([0]="2" [1]="8")
		BASH_ENV=/usr/share/Modules/init/bash
		BASH_LINENO=()
		BASH_REMATCH=([0]=

		.....
	

Using set to reassign positional parameters

     There is no way to reassign positional parameters.... Its a read-only variables...

You can use set command to change the values of positional parameters. if words are given as arguments to set command on the command line,the positional parameters $1,$2,... will be assigned to those words. The previous values stored in the positional parameters will be lost. With in the shell program, call this command

		$~>set one two three
		$~>echo $1-$2-$3
		one-two-three
	

problems with set command...

  • The user input starts with hyphen - symbol
  • The line is completetly white spaces or if the line is null.

To Protect against both of these problems occuring, use the -- option to set. This tells the set not to interpret any subsequenent dashes.

		$~> set -- -1 -2 -3
		$~> echo $(( $1+$2+$3);
		-6	
	

Read command

      Read command reads input from the standard input or from a file descriptor.

Read command splits the line into multiple fields, first word assigned to variable1,second word assigned to variable2 etc.,

Read command maintains 1:1 ration i.e number of fields vs number of variables specified

If number of variables are more than number of fields, remaing variables are set to null

If number of fields are less than fields, last variable has remaining fields.

If no variable is specified, value is stored in $REPLY shell variable.


Read command options
OptionDescription
-a arrayassign the words into indexed , index starts from 0, Check in Arrays section
-d delimitercontinue reading until delimiter character read instead of new line
-n charsreturn after reading n chars, rather than waiting for new line.
-p promptPrompt before reading the input
-rRaw mode, ignore \ as a line-continuation character
-s Do not echo input on terminal
-t timeoutreading input from a terminal or pipe, if no data entered is entered after timeout seconds,returns 1, if preventes application fro hanging forever,or waiting for user input.
-u fdreads from file descriptor n,default is 0


Read Command Example:
	
		$ read line
		This is first line     #user entered data
		
		$ echo $line      #user entered data stored in variable 'line'
		This is first line
	
Read First Name and Last Name
		$ read first last
		jhon hayes
		
		$echo "$first $last"
		jhon hayes
	
Halt Command Execution using Read command
	 	$ read
	 

read command halts the command execution in a program. whenever user presses a Enter key or enters some text then Enter key. in either case,flow continues execution. If User types some text then presses Enter key, text will be stored in $REPLY shell variable.


Prompt User before entering Text. It displays 'first name:' then waits for user input. once user enters text, text stored in variable first

	 	$ read -p 'first name:'  first
	 	first name: hayes
	 	
	 	$echo $first
	 	hayes
	 

Read with File Descriptor(fd)

    Read from a file,instead of standard Input Device. Assign a FD to a file using exec command

Assign some number as a File Descriptor to a file (choose other than 0,1,2)

Read command reads a single line at a time, i.e it reads until it reaches a new line character(\n), so In order to read all lines of a file,loops can be used,

Following example uses while loop to read lines. Once Read command reaches end of file(EOF),loop terminates.

We have file called file.txt
		$ cat file.txt
		This is First Line
		This is Second Line
		This is Third line
	
		#assign file descriptor 
		$ exec 3< file.txt	
		
		$ while read -u 3 line 
		  do
		  	echo $line
		  done
		  
		#OUTPUT
		This is First Line
		This is Second Line
		This is Third line
	
Note: Before attempting this example, programmer must be familiar with IO-Redirections and Loops concepts

ADS