We can concatenate 2 strings by writing them next to each other.
$ var1="dog""cat"
$ echo $var1
dogcat
Placing a space between the words.
$ var1="dog"" ""cat"
$ echo $var1
dog cat
If we have a variable name then we can use the curly braces to separate it from a string if the string is right next to it.
$ echo "${var1}cat"
dogcat
Exercise
1)
Complete the "TO DO" so that "var3" contains the string "dogcat"
var1=dog
var2=cat
var3=TO DO
2)
Capture the output of the commands "date" and "whoami" in a single variable.
If the user name is "user" then the output may look like:
$ echo $var3
Fri, Mar 19, 2021 10:10:35 PM user
Exit Status
str1="Fred and ed go to school."
echo $str1 | grep "ed"
echo $?
echo $str1 | grep "Ed"
echo $?
echo $str1 | grep "Mary"
echo $?
Output:
[amittal@hills Decisions]$ ./decision1.sh
Fred and ed go to school.
0
1
1
The "$?" signifies the exit status . It will print 0 if the previous command succeeded and 1 if the previous command failed. In the previous example when grep finds a match "0" is returned,
If we are writing our own scripts then we need to explicitly state the exit value. By convention, the exit value of a script is 0 if a program succeeded and 1 if the program failed.
Ex:
if [ $# -ne 1 ]
then
echo "Wrong number of Arguments"
exit 1
else
exit 0
fi
Output:
[amittal@hills Decisions]$ ./exit1.sh
Wrong number of Arguments
[amittal@hills Decisions]$ echo $?
1
In the above script we need to state that if there is an error then we return a value of 1 and if there isn't then we return a value of "0" . What if we do not have an exit statement to begin with.
Ex:
if [ $# -ne 1 ]
then
echo "Wrong number of Arguments"
else
:
fi
Output:
[amittal@hills Decisions]$ ./exit2.sh
Wrong number of Arguments
[amittal@hills Decisions]$ echo $?
0
In the above example we do not explicitly return any value and when we look at the exit status we see the value of 0 . We have used the blank statement of colon (":") in the above example to signify a statement that does not do anything.
If Condition
Ex:
var1=10
if [ $var1 -eq 10 ]
then
echo "Inside the if condition"
fi
Output:
[amittal@hills Decisions]$ ./if1.sh
Inside the if condition
The if condition involves an expression inside the square brackets.
[ $var1 -eq 10 ]
The "then" part can also be written after the if condition.
var1=10
if [ $var1 -eq 10 ] ; then
echo "Inside the if condition"
fi
If we write "then" after the "]" then we have to use a semi colon. We can also choose to replace the square brackets with the test condition.
Ex:
var1=10
if test $var1 -eq 10
then
echo "Inside the if condition"
fi
We can decide to use the semi colon also if we place the word "then" in the same line as "if" .
Ex:
var1=10
if test $var1 -eq 10 ; then
echo "Inside the if condition"
fi
What sort of conditions can we place in if. The below sections show the conditions for "String" , "Files", "Numbers" .
Else
File: dec1.sh
var1=1
if [ $var1 -gt 9 ]
then
echo "Step 2"
else
echo "Step 7"
fi
Output:
[amittal@hills Decisions]$ ./dec2.sh
Step 7
The above shows the "else" statement that is executed if the "if" condition is false.
We can also have "elif" statement .
Ex:
var1=11
if [ $var1 -gt 9 ]
then
echo "Step 2"
elif [ $var1 -eq 11 ]
then
echo "Step 7"
fi
Case statement
Similar to "if" we can have a "case" statement.
Ex:
if [ "$#" -ne 1 ]
then
echo "Usage: number digit"
exit 1
fi
case "$1"
in
0) echo zero;;
1) echo one;;
2) echo two;;
3) echo three;;
4) echo four;;
5) echo five;;
6) echo six;;
7) echo seven;;
8) echo eight;;
9) echo nine;;
esac
The ";;" indicates that we should break out of the case statement.
Using Regular Expressions:
File: "case2.cpp"
if [ "$#" -ne 1 ] then echo "Usage: number" exit 1 fi case "$1"in [0-9]) echo "Single Digit Number" ;; [0-9][0-9]) echo "Two Digit Number" ;; [0-9][0-9][0-9]) echo "Three Digit Number" ;; *) echo "Something else." ;;esac
Strings
-n String1 - the length of the String1 variable is nonzero -z String1 - the length of the String1 variable is 0 (zero) String1 = String2 - String1 and String2 variables are identical String1 != String2 - String1 and String2 variables are not identical String1 - true if String1 variable is not a null string
Files
-e FileName - FileName exists
-b Filename - Returns a True exit value if the specified FileName exists and is a block special file -c FileName - FileName is a character special file-d FileName - FileName is a directory-f FileName - FileName is a regular file -g FileName - FileName's Set Group ID bit is set -h FileName - FileName is a symbolic link-k FileName - FileName's sticky bit is set -L FileName - FileName is a symbolic link-p FileName - FileName is a named pipe (FIFO) -r FileName - FileName is readable by the current process -s FileName - FileName has a size greater than 0 -t FileDescriptor - FileDescriptor is open and associated with a terminal-u FileName - FileName's Set User ID bit is set
Exercise:
Write a shell script "dir1.sh" that takes an argument and determines if that
if the argument is a folder or not.
./dir1.sh folder1
"folder1" is a folder.
./dir1.sh file1
"file1" is not a folder.
Numbers
Integer1 -eq Integer2 - Integer1 and Integer2 variables are algebraically equal
-ne - not equal
-gt - greater than
-ge - greater or equal
-lt - less than
-le - less or equal
We can have loops in Shell scripting.
There are many variations of the for loop:
1)
for i1 in 1 2 3
do
echo $i1
done
Output:
[amittal@hills loops]$ chmod 777 loop3.sh
[amittal@hills loops]$ ./loop3.sh
1
2
3
In the "for some variable in" we provide a list of constants. The variable will take on the value of each of the constants and output the value using "echo" . The statements between the "do" and "done" are executed with each iteration.
We can also replace the "do" and "done" with curly braces .
Ex:
for i1 in 1 2 3
{
echo $i1
}
Output:
[amittal@hills loops]$ ./loop4.sh
1
2
3
We can also have the for loop with the syntax as:
Ex:
for i1 in {1..5}
do
echo "$i1"
done
Output:
[amittal@hills loops]$ ./loop5.sh
1
2
3
4
5
We can also specify a step value in the for loop :
Ex:
for i1 in {1..10..2}
do
echo "$i1"
done
Output:
[amittal@hills loops]$ ./loop6.sh
1
3
5
7
9
Here the value of 1 is incremented by 2 till it is greater than 10 and at that time the loop exits.
We can also use shell wildcards in a for loop. A shell wildcard is expanded to say the file names.
Ex:
for i1 in *
do
echo "$i1"
done
Output:
[amittal@hills loops]$ ./loop7.sh
loop1.sh
loop2.sh
loop3.sh
loop4.sh
loop5.sh
loop6.sh
loop7.sh
Break and Continue
The "break" keyword breaks out of a for loop.
Ex:
for i1 in 1 2 3 4 5
do
echo "$i1"
if [ $i1 -eq 3 ]
then
break
fi
done
echo "End of for loop."
Output:
[amittal@hills Break]$ ./br1.sh
1
2
3
End of for loop.
The "continue" keyword continues to the beginning of the for loop. The lines in the block after the "continue" statement are not executed.
Ex:
for i1 in 1 2 3 4 5
do
if [ $i1 -eq 3 ]
then
continue
fi
echo "$i1"
done
echo "End of for loop."
Output:
[amittal@hills Continue]$ ./ct1.sh
1
2
4
5
End of for loop.
We can see that when "$i1" was equal to 3 the echo statement at the bottom was skipped.
We can pass arguments to our shell scripts. There is a separate section on this site that discusses arguments.
We can have functions in a shell script.
Ex:
isEvenOdd(){ #echo "Step2 $1" if [ `expr $1 % 2` -eq 0 ] then #echo "Step3" return 1 else return 0 fi }#echo "Step1 $1" isEvenOdd $1#echo $?if [ $? -eq 1 ] then echo "$1 is an even number"else echo "$1 is an odd number" fi
The function is defined without any parameters. It takes the parameters the same way we pass parameters to the shell using the dollar symbol. In the above code we have written a function called "isEvenOdd" that checks whether the argument is even or odd. It uses the "return" function to return a code. We can obtain this code in the calling place using the "$?" symbol which signifies the return code of executing the function. We need to use this right after we call the function else we might end up with the return code of the functions/commands in the middle.
Exercise
Write a function main and place the statements
isEvenOdd $1
#echo $?
if [ $? -eq 1 ]
then
echo "$1 is an even number"
else
echo "$1 is an odd number"
fi
in the function. Call the main function at the end of the script with a single argument corresponding to what the user types.
main $1
You can use the function "isEvenOdd" from the above section.
$ ./even2.sh 2
2 is an even number
$ ./even2.sh 23
23 is an odd number
Input
We can use the "read" command to read the input into a variable.
File: "i1.sh"
echo Input your name
read varname
echo It\'s nice to meet you $varname
1)
Write a shell program that prints out even numbers and the sum of a number and the numbers below it. So sum of 4 will be
4 + 3 + 2 + 1 = 10
2)
From Chapter 7 of the book Unix Shell Programming
Write a program called home that takes the name of a user as its single argument and prints that
user's home directory. So
home steve
would print
/users/steve
if /users/steve is steve's home directory. (Hint: Recall that the home directory is the sixth
field stored in the file /etc/passwd.)
3)
The date command prints out the date and time.
$ date
Sat, Mar 13, 2021 7:42:55 AM
Create a folder called "exb" and in it create a folder called "source" and create some files in it. Write a script that will create a folder using the output of the date command and copy the files from the source folder to this folder. For the output above our folder will have the name:
backup_2021_Mar_13_7_42_55
We give an argument to the script specifying the folder to back up and the script creates a backup folder in the same directory.
Ex:
$ ls
1 backup1.sh
We have a folder named "1" and our script.
$ ./backup1.sh 1
$ ls
1 backup_2021_Mar_20_6_32_11 backup1.sh
1)
isEvenOdd()
{
if [ `expr $1 % 2` -eq 0 ]
then
return=1
else
return=0
fi
}
sum()
{
for (( i1=1; i1<=$1; i1++ ))
{
return=$(($return + i1))
}
echo $return
}
sum 4
isEvenOdd 24
if [ $return -eq 1 ]
then
echo "Number is even."
else
echo "Number is odd."
fi
isEvenOdd()
{
if [ `expr $1 % 2` -eq 0 ]
then
return=1
else
return=0
fi
}
sum()
{
for (( i1=1; i1<=$1; i1++ ))
{
return=$(($return + i1))
}
echo $return
}
sum 4
isEvenOdd 24
if [ $return -eq 1 ]
then
echo "Number is even."
else
echo "Number is odd."
fi
From Chapter 7 of the book Unix Shell Programming
Write a program called home that takes the name of a user as its single argument and prints that
user's home directory. So
home steve
would print
/users/steve
if /users/steve is steve's home directory. (Hint: Recall that the home directory is the sixth
field stored in the file /etc/passwd.)
cat /etc/passwd | awk -v user1=$1 'BEGIN { FS=":" ; } { if ( $1 == "amittal" ) { print $6 } }'
cat /etc/passwd | grep amittal | awk 'BEGIN { FS=":" } { print $6 }'
3)
#Sat, Mar 13, 2021 7:42:55 AM
if [ $# -ne 1 ]
then
echo "Please enter the name of the folder to backup."
exit 1
fi
name1="backup"
var1=`date | awk '{print $4}'`
name1=${name1}_${var1}
echo $name1
var1=`date | awk '{print $2}'`
name1=${name1}_${var1}
var1=`date | awk '{print $3}'`
name1=${name1}_${var1}
echo $name1
var1=`date | awk '{print $5}'`
echo $var1
var1=`echo $var1 | sed 's/:/_/g'`
echo $var1
name1=${name1}_${var1}
name1=`echo $name1 | sed 's/,//g'`
echo $name1
mkdir $name1
cp -R $1 $name1
Reading and Writing
Integer Arithmetic