Linux

 

 

 

 

Shell Programming

 

Shell Programming is a kind of programming that is designed mainly to automate a sequence of procedures you are manualling doing in a shell (a command prompt). Shell on Linux is similar to Command Prompt program on Windows and Shell Programming is similar to programming a batch file (*.bat file or *.cmd file) on Windows PC. So if you have any experience of creating a batch file (even a very simple one), you would understand easily the concept of Shell programming.

 

If you are not familiar with computer programming, you would get scared of the word 'programming'. But don't get scared too much. You can start Shell programming with very simple application as in Example 1. In the example, you just add a couple of Linux command in a specific shell file that already exists in the system. Just try to modify a system shell file (e.g, rc.local) as in Example 01 to fit your purpose and then move to other cases like creating your own shell program files.

 

 

 

 

Example 01 > Running a program on Boot (Automatic execution of a program during Linux booting)

 

In this example, I will show you an example script that run a program (tightvncserver in this example) while Linux is booting. There are roughly two ways to run a program on Boot. One method is to create a script in init.d directory and the other one is to add shell command in rc.local file. Creating the script in init.d is a nicer and professional way but it is more complicated because it has several requirements you have to follow. So, in this example I will take the simpler way that is using rc.local file.

 

I wrote it in several lines, but it can be 'one line' script or 'one page' script depending on how robustly you want to implement it. For example, in this example the blue parts are the source script to run a program... it can be just a single line script with sudo /usr/bin/tightvncserver :1 .. all the other lines are to print out some informations into a log file so that you can troubleshoot if something happens. In this example, I assumed that the program tightvncserver is already installed on my Linux. If you want to make the script even more robust, you can add more lines to check whether the program is installed or not and make the script even longer and confusing :)

 

In most Linux distribution, rc.local file is in /etc directory (if not, first find where this file is located). Open the file in any text editor you like and add code as highlighted in blue.

 

# following line looks like a comment, but this is not a simple comment. It indicates where your shell is located.

# so you may need to change this line depending on the specific Linux distribution that you are using.

# In my case, I am writing this for Debian running on my Beaglebone board.

# In the original rc.local file, this line used to be #!/bin/sh -e but I removed -e option. If you put -e option, the script

# would quit when an error happens and does not run any script after the error points. If you are running or doing only

# one job here, it may be good to have -e option, but if you want to run many other programs (doing many other

# jobs), -e option would cause problem because all the other jobs after the point of the first error would not get even

# tried

#!/bin/sh

#

# rc.local

#

# This script is executed at the end of each multiuser runlevel.

# Make sure that the script will "exit 0" on success or any other

# value on error.

#

# In order to enable or disable this script just change the execution

# bits.

#

# By default this script does nothing.

 

# Following is to print out a message into a file named bootlog. If this file does not exists, echo command create

# the file first and then write the message in it. so you don't need to worry about whether the file exists or not.

echo "$(date) : Running tightVNC Server" >> /tmp/bootlog

 

# Following is the main part. it is to run tightvncserver. Note that I put sudo at the beginning. Since rc.local runs

# before you log into the system, even tough you have a full permission (root account) the program may not

# be excuted without sudo or su.

sudo /usr/bin/tightvncserver :1

 

# Following is to print out the status (success or fail) of the previous execusion into bootlog file for troubleshooting.

# Note that you need to put a space right after '[' and right before ']'.

if [ $? -eq 0 ]; then

   echo "$(date) : tightVNC Server Run : Success " >> /tmp/bootlog

else

   echo "$(date) : tightVNC Server Run : Fail " >> /tmp/bootlog

fi

 

exit 0

 

 

 

Example 02 > 'Hello World'.

 

 

This is the first program that you can try with your own shell program file named HelloWorld. Create HelloWorld file as shown below. Main purpose of this example is not to show you the shell programming syntax (it is too simple) but to show how to make the text file as a runnable file and run it.  You should be familiar with the procedures shown here and I will not explain about these steps in other examples.

 

 

< Creating a code >

 

HelloWorld

#!/bin/sh -e

 

echo 'Hello World !'

 

 

list files in the folder and you see the file is created as read/right, but not executable as highlighted in blue.

 

    sharetechnote@sharetechnote-VirtualBox:~/shell$ ls -al

     

    total 12

    drwxrwxr-x  2 sharetechnote sharetechnote 4096 Jan 19 22:34 .

    drwxr-xr-x 17 sharetechnote sharetechnote 4096 Jan 19 22:31 ..

    -rw-rw-r--  1 sharetechnote sharetechnote   21 Jan 19 22:34 HelloWorld

 

 

< Try run and FAIL >

 

Let's try to run the program anyway as shown below. Actually this is not to correct way to run the script file in the current folder, but tried to show you an example of bad case.

 

    sharetechnote@sharetechnote-VirtualBox:~/shell$ HelloWorld

     

    HelloWorld: command not found

 

 

The correct way to run the file in the current folder is as follows. As you see in Basic Linux Command page, './' indicate the 'Current Directory'. But you got another error as shown below.

 

    sharetechnote@sharetechnote-VirtualBox:~/shell$ ./HelloWorld

     

    bash : ./HelloWorld : permission denied

 

 

< Making the code Executable >

 

This error came out because the file is not set as executable. You can change the file to be read/write/executable as shown below.

 

    sharetechnote@sharetechnote-VirtualBox:~/shell$ chmod 777 HelloWorld

 

 

Then you can confirm that the file is properly set to be  read/write/executable as shown below.

 

    sharetechnote@sharetechnote-VirtualBox:~/shell$ ls -al

     

    total 12

    drwxrwxr-x  2 sharetechnote sharetechnote 4096 Jan 19 22:34 .

    drwxr-xr-x 17 sharetechnote sharetechnote 4096 Jan 19 22:31 ..

    -rwxrwxrwx  1 sharetechnote sharetechnote   21 Jan 19 22:34 HelloWorld

 

 

< RUN the Code >

 

Then try run the file again. Now you get the correct result as shown below.

 

    sharetechnote@sharetechnote-VirtualBox:~/shell$ ./HelloWorld

     

    Hello World !

 

There is another way to run the code as follows. Personally I don't use this way often.

    sharetechnote@sharetechnote-VirtualBox:~/shell$ sh HelloWorld

     

    Hello World !

 

There is another way to run the code as follows. Personally I don't use this way often either. (NOTE : If your Linux does not support bash shell, this command would not work)

 

    sharetechnote@sharetechnote-VirtualBox:~/shell$ bash HelloWorld

     

    Hello World !

 

 

< Making it Runnable from Anywhere >

 

This is not a required step. So it is up to you whether you do this or not. You can run the code as shown above, but you may see some problem here (it would not look as a problem depending on your purpose though). The first issue is that you need to put './' whenever you run the code and the second one is that you cannot run the code from other directories (this is not impossible, but you always need to put the full path of the code).

If you run the code just like a regular linux command, you need to put the code into a specific folder '/usr/bin' (this is the case for Ubuntu, it may be a different folder if you are using different Linux.). To do this, try followings

 

    sharetechnote@sharetechnote-VirtualBox:~/shell$ sudo cp HelloWorld usr/bin

or

    sharetechnote@sharetechnote-VirtualBox:~/shell$ sudo mv HelloWorld usr/bin

 

NOTE : /usr/bin is a special folder for which you would need a special permission to get access. That's why you need to put 'sudo' in the command.

 

 

 

Example 03 > Setting and Referencing Variables

 

 

PrintVar1

#!/bin/sh -e

 

msg='Hello World !'

timeStamp=$(date)

 

echo "$msg on $timeStamp"

echo "${msg} on ${timeStamp}"

printf "$msg on $timeStamp\n"

printf "${msg} on ${timeStamp}\n"

 

    sharetechnote@sharetechnote-VirtualBox:~/shell$ ./PrintVar1

     

    Hello World ! on Fri Jan 19 23:42:06 EST 2018

    Hello World ! on Fri Jan 19 23:42:06 EST 2018

    Hello World ! on Fri Jan 19 23:42:06 EST 2018

    Hello World ! on Fri Jan 19 23:42:06 EST 2018

 

 

NOTE : when you assign a value to a variable, you should be careful of using space (whitespace) in it. I think how to handle the whitespace in variable assign, but I think 'not to use any space in the assignment' would be the safest way. For example, try followings in the code in this example and see how it works. In the shell that I am using now, none of the followings works.

    Case i) msg= 'Hello World !'

    Case ii) msg ='Hello World !'

    Case iii) msg = 'Hello World !'

 

 

 

Example 04 > Passing Command Line Arguments

 

You can take in command line argument via special variable name $1, $2, $3 etc (This is same as Windows Batch File)

 

CmdLineArg1

#!/bin/sh -e

 

echo "arg1 = $1"

echo "arg2 = $2"

echo "script name = $0"

echo "all args = $@"

 

    sharetechnote@sharetechnote-VirtualBox:~/shell$ ./CmdLineArg1 -flag myfile.txt

     

    arg1 = -flag

    arg2 = myfile.txt

    script name = ./CmdLineArg1

    all args = -flag myfile.txt

 

 

If you don't specify any argument and run the shell code, you will get the following result (It doesn't cause any error).

 

    sharetechnote@sharetechnote-VirtualBox:~/shell$ ./CmdLineArg1

     

    arg1 =

    arg2 =

    script name = ./CmdLineArg1

    all args =

 

 

 

Example 05 > Finding / Replacing Substring

 

 

           NOTE: The first line of this scrip says '#!/bin/bash' implying that this scrip can work properly

                     only in bash shell.

StringEx1

#!/bin/bash

 

msg="home/desktop/shell/file/txt"

 

echo "The original string = $msg"

echo "The Length of String = ${#msg}"

echo "The Substring Starting from position 3 = ${msg:3}"

echo "The Substring Starting from position 3 with length of 4 = ${msg:3:10}"

echo "Delete the substring before the first / = ${msg#*/}"

echo "Delete the substring after the last / = ${msg%/*}"

echo "Delete the substring after the first / = ${msg##*/}"

echo "Delete the substring before the last / = ${msg%%/*}"

echo "Replace a first / to . = ${msg/'/'/.}"

echo "Replace all / to . = ${msg//'/'/.}"

 

    sharetechnote@sharetechnote-VirtualBox:~/shell$ ./StringEx1

     

    The original string = home/desktop/shell/file/txt

    The Length of String = 27

    The Substring Starting from position 3 = e/desktop/shell/file/txt

    The Substring Starting from position 3 with length of 4 = e/desktop/

    Delete the substring before the first / = desktop/shell/file/txt

    Delete the substring after the last / = home/desktop/shell/file

    Delete the substring after the first / = txt

    Delete the substring before the last / = home

    Replace a first / to . = home.desktop/shell/file/txt

    Replace all / to . = home.desktop.shell.file.txt

 

 

 

Example 06 > Recieving UserInput on Run Time

 

 

UserInput1

#!/bin/sh

 

echo "Type in your secret word"

 

read SECRET_WORD

 

echo "You typed in $SECRET_WORD as a secret word"

 

    sharetechnote@sharetechnote-VirtualBox:~/shell$ ./UserInput1

     

    Type in your secret word

    _      # Type in any words in the keyboard and Press Enter

     

    SHARETECHNOTE # Typed in a word and Pressed Enter   

     

    You typed in SHARETECHNOTE as a secret word  # This is the output   

 

 

 

Example 07 > If Statement

 

 

< Comparison Operator >

-eq

equal to

-ne

not equal to

-lt

less than

-le

less than or equal to

-gt

greater than

-ge

greater than or equal to

 

< File Status Operator >

-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

 

 

IfEx1

#!/bin/sh

 

echo "Enter your score:"

read SCORE

 

if [ "$SCORE" -lt 60 ]; then

    echo "Your Grade is F."

elif [ "$SCORE" -ge 60 ] && [ "$SCORE" -lt 70 ]; then

    echo "Your Grade is D."

elif [ "$SCORE" -ge 70 ] && [ "$SCORE" -lt 80 ]; then

    echo "Your Grade is C."

elif [ "$SCORE" -ge 80 ] && [ "$SCORE" -lt 90 ]; then

    echo "Your Grade is B."

else

    echo "Your Grade is A." 

fi

 

    sharetechnote@sharetechnote-VirtualBox:~/shell$ ./IfEx1

     

    Enter your score:  # Type in your score when you see this prompt

     

    95   # This is what I typed in

     

    Your Grade is A. # this is the output

     

 

 

 

Example 08 > for loop

 

 

           NOTE: The first line of this scrip says '#!/bin/bash' implying that this scrip can work properly

                     only in bash shell.

forEx1

#!/bin/bash

 

for num in {1..10}

do

    echo "$num" 

done

 

    sharetechnote@sharetechnote-VirtualBox:~/shell$ ./forEx1

     

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

 

 

           NOTE: The first line of this scrip says '#!/bin/bash' implying that this scrip can work properly

                     only in bash shell.

forEx2

#!/bin/bash

 

for num in {1..10..2}

do

    echo "$num" 

done

 

    sharetechnote@sharetechnote-VirtualBox:~/shell$ ./forEx2

     

    1

    3

    5

    7

    9

     

 

 

           NOTE: The first line of this scrip says '#!/bin/bash' implying that this scrip can work properly

                     only in bash shell.

           NOTE : Notice that double parathesis '((' and '))' should be used.

forEx3

#!/bin/bash

 

for((num = 1; num <= 10; num += 2))

{

    echo "$num" 

}

 

    sharetechnote@sharetechnote-VirtualBox:~/shell$ ./forEx3

     

    1

    3

    5

    7

    9

 

 

 

 

Reference :

 

[1]