Operating System Lab Manual Final Print
Operating System Lab Manual Final Print
LAB
MANUAL
Course: CSC322-Operating Systems
Learning Procedure
1) Stage J (Journey inside-out the concept)
2) Stage a1 (Apply the learned)
3) Stage v (Verify the accuracy)
4) Stage a2 (Assess your work)
Table of Contents
LAB # 01
Statement Purpose:
This lab will introduce the Linux Operating System to you. You will learn the how to create
VM using Virtual-Box, Installing Ubuntu on VM and the basic syntax of Linux Commands
Activity Outcomes:
This lab teaches you the following topics:
Instructor Note:
As pre-lab activity, read Chapter 1 to 6 from the book “The Linux Command Line”, William E.
Shotts, Jr.
1) Stage J (Journey)
1. Linux
Linux is a generic term referring to Unix-like computer operating systems based on the Linux kernel.
Their development is one of the most prominent examples of free and open source software
collaboration; typically all the underlying source code can be used, freely modified, and
redistributed by anyone. Many quantitative studies of free / open source software focus on topics
including market share and reliability, with numerous studies specifically examining Linux. The Linux
market is growing rapidly.
1.1 History
All modern operating systems have their roots in 1969 when Dennis Ritchie and Ken Thompson
developed the C language and the Unix operating system at AT&T Bell Labs. They shared their
source code (yes, there was open source back in the Seventies) with the rest of the world, including
the hippies in Berkeley California. By 1975, when AT&T started selling Unix commercially, about half
of the source code was written by others. The hippies were not happy that a commercial company
sold software that they had written; the resulting (legal) battle ended in there being two versions of
Unix: the official AT&T Unix, and the free BSD Unix.
In the Eighties many companies started developing their own Unix: IBM created AIX, Sun SunOS
(later Solaris), HP HP-UX and about a dozen other companies did the same. The result was a mess
of Unix dialects and a dozen different ways to do the same thing. And here is the first real root of
Linux, when Richard Stallman aimed to end this era of Unix separation and everybody re-inventing
the wheel by starting the GNU project (GNU is Not Unix). His goal was to make an operating system
that was freely available to everyone, and where everyone could work together (like in the
Seventies). Many of the command line tools that you use today on Linux are GNU tools.
The Nineties started with Linus Torvalds, a Swedish speaking Finnish student, buying a 386
computer and writing a brand new POSIX compliant kernel. He put the source code online, thinking
it would never support anything but 386 hardware. Many people embraced the combination of this
kernel with the GNU tools, and the rest, as they say, is history. Linux kernel version 4.0 was
released in April 2015. Its source code grew by several hundred thousand lines (compared to
version 3.19 from February 2015) thanks to contributions of thousands of developers paid by
hundreds of commercial companies including Red Hat, Intel, Samsung, Broadcom, Texas
Instruments, IBM, Novell, Qualcomm, Nokia, Oracle, Google, AMD and even Microsoft (and many
more).
1.2 Popularity
Today more than 97 percent of the world's supercomputers (including the complete top 10), more
than 80 percent of all smartphones, many millions of desktop computers, around 70 percent of all
web servers, a large chunk of tablet computers, and several appliances (DVD players, washing
machines, DSL modems, routers, self-driving cars, space station laptops...) run Linux. Linux is by far
the most commonly used operating system in the world.
The Linux kernel: This is a small, but essential part of an operating system. The kernel is responsible
for interfacing with a device’s hardware, providing services to the rest of the system, and
performing tasks such as managing the device’s CPU and memory. The Linux kernel, like any kernel,
can only function as part of a wider operating system. It’s impossible to have an operating system
that consists solely of a Linux kernel. Since Android is a complete operating system, we can
immediately rule out classifying Android as a Linux kernel.
A Linux distribution or distro: This is an operating system that contains the Linux kernel and
additional software such as utilities, libraries and a GUI, plus pre-installed applications such as web
browsers, text editors, and music players. Even if this additional software was designed specifically
to run on the Linux kernel, it’s not part of the Linux kernel. When discussing operating systems that
use the Linux kernel, the terms ‘distribution,’ ‘distro’ and ‘operating system’ are interchangeable.
Since anyone can take the Linux kernel, add their own software, and create a complete operating
system, there are countless Linux distros currently available.
A Linux distribution -- often shortened to "Linux distro" -- is a version of the open source Linux
operating system that is packaged with other components, such as an installation programs,
management tools and additional software such as the KVM hypervisor. Linux distributions, which
are based on the Linux kernel, are often easier for users to deploy than the traditional open source
version of Linux. This is because most distributions eliminate the need for users to manually
compile a complete Linux operating system from source code, and because they are often
supported by a specific vendor.
Hundreds of Linux distributions are available today, and each targets specific users or systems such
as desktops, servers, mobile devices or embedded devices. Most distributions come ready to use,
while others are packaged as source code that a user must compile during installation. A list of
most popular Linux distros is given below
1. Ubuntu
2. Slackware
3. SuSE
4. Debain
5. RedHat
6. Fedora
7. Turbo Linux
In this course, we will use the Ubuntu distro. Ubuntu is a popular and to use graphical Linux distro.
It was developed and released by Canonical Ltd. in 2004. It is freely available and can be
downloaded from http://www.ubuntu.com/download/desktop.
2. Installing Ubuntu
Before discussing the options available to install Ubuntu, we discuss the basic system requirement.
It is recommended to Ubuntu should be installed on a system that has a 2 GHz dual core processor
with 2GB RAM and 25GB of free hard disk space.
There are many ways to use Ubuntu. It can be installed on a system as a stand-alone OS. Similarly,
it can be installed as multi-boot system where it is installed on a system that already has any other
OS like windows. Further, it can also be used without installing from a bootable USB. However, in
this course we will run the Ubuntu on virtual machine. To create virtual machine we will use Oracle
VM Virtual-box. In the following, first we give an overview of Virtual-Box and then discuss the
installation process of Ubuntu on VM.
Virtual-Box is a cross-platform virtualization application. What does that mean? For one thing, it
installs on your existing Intel or AMD-based computers, whether they are running Windows, Mac,
Linux or Solaris operating systems. Secondly, it extends the capabilities of your existing computer
so that it can run multiple operating systems (inside multiple virtual machines) at the same time.
So, for example, you can run Windows and Linux on your Mac, run Windows Server 2008 on your
Linux server, run Linux on your Windows PC, and so on, all alongside your existing applications.
You can install and run as many virtual machines as you like -- the only practical limits are disk
space and memory. Virtual-Box can be downloaded from https:// www.virtualbox.org/ wiki/
Downloads for free.
Before installing the Ubuntu, we need to ensure that Virtual-Box has been installed on the machine
and a compatible version of Ubuntu has been downloaded. To install Ubuntu on VM we need to
create a virtual machine on Virtual-Box. The process to create a VM on Virtual-Box is given below.
Step 1: Start the Virtual-Box and click the new button to start creating a new VM
Step 5: Select the hard disk file type and press the Next button
Step 6: Select the storage type on Physical hard disk and press Next
Step 7: Select the location and size on physical hard disk to store the VM and press the Create
button
It completes the creation process of VM on Virtual-Box. The newly created VM can be seen on main
screen
To install Ubuntu on the newly created VM, we need to attach the Ubuntu installation file with it. It
can be done as given below.
Step 1: Select the VM on main screen of Virtual-Box and click the settings button. The following
window will appear.
Step 2: Select the storage button as highlighted in the above figure. The following window will
appear
Step 3: Select + button (as highlighted in above figure) and browse and select the Ubuntu
installation file downloaded earlier. Now, press the OK button to complete the process of attaching
Ubuntu with VM.
Once the VM has been created and Ubuntu Installation file is attached with it, we can start the
installation process. To do this, select the VM on main window of Virtual-Box and click the start
button as given below.
Now, the booting process will start and the following window will be appeared.
Here, we can try the Ubuntu without installing. To install Ubuntu, click Install Ubuntu button. The
next screen gives you 2 options. One is to download updates in the background while installing and
the other is to install 3rd party software. Check the option to install 3 party software. Then click the
Continue button.
There is an option to encrypt the installation. This is so that if anybody else were to steal the
data, they would not be able to decrypt the data.
Finally, Linux offers a facility called LVM, which can be used for taking snapshots of the disk.
For the moment, to make the installation simple, let’s keep the options unchecked and proceed with
the installation by clicking the Install Now button.
In the following screen, we will be prompted if we want to erase the disk. Click the Continue button
to proceed.
In next screen, we will be asked to confirm our location. Click the Continue button to proceed.
10
Now, we will be asked to confirm the language and the keyboard settings. Let us select English (UK)
as the preferred settings.
In the following screen, we will need to enter the user name, computer name and password which
will be used to log into the system. Fill the necessary details as shown in the following screenshot.
Then, click the continue button to proceed.
The system will now proceed with the installation and we will see the progress of the installation as
shown in the following screenshot.
11
At the end of the installation, the system will prompt for a restart. Click the Restart Now to proceed.
When the installation is completed, we can login into the system. To do this, start the Virtual-Box
and select the VM and start it. The following screen will appear
By entering username and password, we can login to the system and the following window will
appear
12
We can open the terminal by typing Ctrl + Alt + T short-key or by right-clicking the mouse and
selecting the Open New Terminal option. The terminal window looks like given below.
A shell is a program that reads commands that are typed on a keyboard and then executes (i.e.,
runs) them. Shells are the most basic method for a user to interact with the system.
13
Most commands use options consisting of a single character preceded by a dash, for example, “-l”,
but many commands, including those from the GNU Project, also support long options, consisting
of a word preceded by two dashes. Also, many commands allow multiple short options to be strung
together.
Command History
Most Linux distributions remember the last 500 commands by default. Press the down-arrow key
and the previous command disappears.
1. Date Command: This command is used to display the current data and time.
Syntax:
$date
$date +%ch
Options:
a = Abbreviated weekday.
A = Full weekday.
b = Abbreviated month.
B = Full month.
c = Current day and time.
C = Display the century as a decimal number.
d = Day of the month.
D = Day in „mm/dd/yy‟ format
h = Abbrevated month day.
H = Display the hour.
L = Day of the year.
m = Month of the year.
M = Minute.
P = Display AM or PM
S = Seconds
T = HH:MM:SS format
u = Week of the year.
y = Display the year in 2 digit.
Y = Display the full year.
Z = Time zone
To change the format:
Syntax:
$date „+%H-%M-%S‟
2. Calendar Command: This command is used to display the calendar of the year or the particular
month of calendar year.
Syntax :
a.$cal <year>
b.$cal <month> <year>
Here the first syntax gives the entire calendar for given year & the second Syntax gives
the calendar of reserved month of that year.
3. To see the current amount of free space on your disk drives, enter df:
14
4. Likewise, to display the amount of free memory, enter the free command.
5. We can end a terminal session by either closing the terminal emulator window, or by entering
the exit command at the shell prompt
6. ’who’ Command: It is used to display who are the users connected to our computer currently.
Syntax:
$who – option‟s
Options : -
H–Display the output with headers
b–Display the last booting date or time or when the system was lastly rebooted
9. MAN’ Command: It help us to know about the particular command and its options & working. It
is like„help‟ command in windows .
Syntax:
$man <command name>
2) Stage a1 (apply)
Lab Activities:
Activity 1:
In this activity, you are required to perform tasks given below:
Solution:
1. date
2. cal 2019
3. cal 2012
4. cal 2 2012
15
Activity 2:
Perform the following tasks using Linux CLI commands
1. Display the amount of free storage on your machine
2. Display the amount of free memory on your machine
3. Display the user name of the current user
4. Open the man of date free command
Solution:
1. df
2. free
3. who
4. man date
3) Stage v (verify)
Home Activities:
1. In GUI open the Libre Office writer tool create a document that contains information
about your favorite place. Try the following short- keys while formatting the
document
4) Stage a2 (assess)
Lab Assignment and Viva voce
16
LAB # 02
Statement of Purpose:
This lab will introduce the Directory and File related commands to you. We will start with
the some basic but important commands used to navigate through the Linux file system.
Then we will discuss Directory and File related commands. Finally, we will introduce the I/O
redirection in Linux
Activity Outcomes:
This lab teaches you the following topics:
Instructor Note:
As pre-lab activity, read Chapter 1 to 6 from the book “The Linux Command Line”, William E.
Shotts, Jr.
17
1) Stage J (Journey)
Introduction
Linux organizes its files in a hierarchical directory structure. The first directory in the file
system is called the root directory. The root directory contains files and subdirectories,
which contain more files and subdirectories and so on and so on. If we map out the files and
directories in Linux, it would look like an upside-down tree. At the top is the root directory,
which is represented by a single slash (/). Below that is a set of common directories in the
Linux system, such as bin, dev, home, lib , and tmp , to name a few. Each of those
directories, as well as directories added to the root, can contain subdirectories.
1. Navigation
The first thing we need to learn is how to navigate the file system on our Linux system. In
this section we will introduce the commands used for navigation in Linux system.
The directory we are standing in is called the current working directory. To display the
current working directory, we use the pwd (print working directory) command. When we
first log in to our system our current working directory is set to our home directory.
Suppose, a user is created with name me on machine Ubuntu; we display its current
working directory as given below
To list the files and directories in the current working directory, we use the ls command.
Suppose, a user me is in its home directory; to display the contents of current working
directory can be displayed as follows:
Besides the current working directory, we can specify the directory to list, like so:
Or even specify multiple directories. In this example we will list both the user's home
directory (symbolized by the “~” character) and the /usr directory:
18
To change your working directory, we use the cd command. To do this, type cd followed
by the pathname of the desired working directory. A pathname is the route we take along
the branches of the tree to get to the directory we want. Pathnames can be specified in one
of two different ways; as absolute pathnames or as relative pathnames. An absolute
pathname begins with the root directory and follows the tree branch by branch until the
path to the desired directory or file is completed. On the other hand a relative pathname
starts from the working directory.
Suppose, a user me is in its home directory and we want to go into the Desktop
directory, then it can be done as follows:
The “..” operator is used to go to the parent directory of the current working directory. In
continuation of the above example, suppose we are in the Desktop directory and we have to
go to the Documents directory. To this task, first we will go the parent directory of Desktop
(i.e. me, home directory of the user) that contains the Documents directory then we will go
into the Documents directory as given below.
19
In this Section, we introduce the most commonly used commands related to Directories.
In Linux, mkdir command is used to create a directory. We pass the directory name as the
argument to the mkdir command. Suppose, the user me is in its home directory and we
want to create a new directory named mydir in the Desktop directory. To do this, first we
will change the current directory to Desktop and then we will create the new directory. It is
shown below:
Multiple directories can also be created using single mkdir command as given below:
cp command is used to copy files and directories. The syntax to use cp command is given
below:
Here, item1 and item2 may be files or directories. Similarly, multiple files can also be copied
using single cp command.
mv command is used to move files and directories. This command can also be used to
rename files and folder. To rename files and directories, we just perform the move
operation with old name and new name. As a result, the files or directory is created again
with a new name. The syntax to use mv command is given below:
20
To remove or delete a files and directories, rm command is used. Empty directories can also
be deleted using rmdir command but rm can be used for both empty and non-empty
directories as well as for files. The syntax is given below:
In Linux, there are several ways to create an empty text file. Most commonly the touch
command is used to create a file. We can create a file with name myfile.txt using touch
command as given below:
Similarly, a file can be created using some editors. For example, to create a file using gedit
editor
21
Another option to view the contents of a text file is the use of less command.
cat command is also used to append a text file. Suppose we want to add some text at the
end of myfile.txt
Now, type the text and enter ctrl+d to copy the text to myfile.txt.
Using cat command, we can view the contents of multiple files. Suppose, we want to view
the contents of file1, file2 and file3, we can use the cat command as follows:
Similarly, we can redirect the output of multiple files to file instead of screen using cat
command. Suppose, in the above example we want to write the contents of file1, file2 and
file3 into another file file4 we can do this as shown below:
To determine the type of a file we can use the file command. The syntax is given below:
4. Redirecting I/O
Many of the programs that we have used so far produce output of some kind. This output
often consists of two types. First, we have the program's results; that is, the data the
program is designed to produce, and second, we have status and error messages that tell us
how the program is getting along. If we look at a command like ls, we can see that it displays
its results and its error messages on the screen.
Keeping with the Unix theme of “everything is a file,” programs such as ls actually send their
results to a special file called standard output (often expressed as stdout) and their status
messages to another file called standard error (stderr). By default, both standard output and
standard error are linked to the screen and not saved into a disk file. In addition, many
programs take input from a facility called standard input (stdin) which is, by default,
attached to the keyboard. I/O redirection allows us to change where output goes and where
input comes from. Normally, output goes to the screen and input comes from the keyboard,
but with I/O redirection, we can change that.
22
I/O redirection allows us to write the output on another file instead of standard output i.e.
screen. To do this, we use the redirection operator i.e. <. For example, we want to write the
output of ls command in a text file myfile.txt instead of screen. This can be done as given
below:
If we write the output of some other program to myfile.txt using > operator, its previous
contents will be overwritten. Now, if want to append the file instead of over-writing we can
use the << operator.
Redirecting input enables us to take input from another file instead of standard input i.e.
keyboard. We have already discussed this in previous section while discussing cat command
where we used the text file as input instead of keyboard and wrote it to another file.
4.3 Pipelines
The ability of commands to read data from standard input and send to standard output is
utilized by a shell feature called pipelines. Using the pipe operator “|” (vertical bar), the
standard output of one command can be piped into the standard input of another:
2) Stage a1 (apply)
Lab Activities:
Activity 1:
In this activity, you are required to perform tasks given below:
23
Solution:
1. pwd
2. cd /etc
3. cd ..
4. cd /
5. ls
6. ls -l
7. ls /etc
8. ls /bin /sbin
9. ls ~
10. ls -al ~
11. ls -lh /boot
Activity 2:
Perform the following tasks using Linux CLI
5. Create a directory “mydir1” in Desktop Directory. Inside mydir1 create another
directory “mydir2”.
6. Change your current directory to “mydir2” using absolute path
7. Now, change you current directory to Documents using relative path
8. Create mydir3 directory in Documents directory and go into it
9. Now, change your current directory to mydir2 using relative path
Solution:
1. cd /home/Ubuntu/Desktop (suppose the user name is ubuntu)
mkdir mydir1
cd mydir1
mkdir mydir2
2. cd /home/ubuntu/Desktop/mydir1/mydir2
3. cd ../../../Desktop
4. mkdir mydir3
cd mydir3
5. cd ../../Desktop/mydir1/mydir2
Activity 3:
Considering the directories created in Activity 2, perform the following tasks
1. Go to mydir3 and create an empty file myfile using cat command
2. Add text the text “Hello World” to myfile
3. Append myfile with text “Hello World again”
24
Solution:
1. cd /home/Documents/mydir3 (suppose the user name is ubuntu)
cat >myfile
4. cat myfile
Activity 4:
Considering the above activities, perform the following tasks
1. move myfile to mydir1
2. copy myfile to mydir2
3. copy mydir2 on Desktop
4. delete mydir1 (get confirmation before deleting)
5. Rename myfile to mynewfile
Solution:
1. mv /home/ubuntu/Document/mydir3/myfile /home/ubuntu/Desktop/mydir1
2. cp /home/ubuntu/Desktop/mydir1/mydir3/myfile
/home/ubuntu/Desktop/mydir1/mydir2
3. cp -r /home/ubuntu/Desktop/mydir1/mydir2 /home/ubuntu/Desktop
4. rm -ri /home/ubuntu/Desktop/mydir1
5. mv /home/ubuntu/Desktop/mydir2/myfile
/hoem/ubuntu/Desktop/mydir2/mynewfile
Activity 5:
This activity is related to I/O redirection
1. Go to Desktop directory
25
Solution:
1. cd /home/ubuntu/Desktop
2. ls -l > out-put-file
3. cat out-put-file
3) Stage v (verify)
Home Activities:
1. Considering the lab activities, perform the following tasks
1. Go to Desktop directory
2. write the contents of mynewfile to newfile
3. view the output of both mynewfile and newfile on screen
4. write the combined output of mynewfile and newfile to a third file out-put-file
2. Long list all files and directories in your system and write out-put on a text-file.
4) Stage a2 (assess)
Lab Assignment and Viva voce
26
LAB # 03
Statement of Purpose:
This lab will introduce the basic concept of file access permissions and package
management in Linux to you.
Activity Outcomes:
This lab teaches you the following topics:
27
1) Stage J (Journey)
1. File Permissions
Linux is a multi-user system. It means that more than one person can be using the computer at the
same time. While a typical computer will likely have only one keyboard and monitor, it can still be
used by more than one user. For example, if a computer is attached to a network or the Internet,
remote users can log in via ssh (secure shell) and operate the computer. In fact, remote users can
execute graphical applications and have the graphical output appear on a remote display.
In a multi-user environment, to ensure the operational accuracy, it is required to protect the users
from each other. After all, the actions of one user could not be allowed to crash the computer, nor
could one user interfere with the files belonging to another user.
1.1 id command
In the Linux security model, a user may own files and directories. When a user owns a file or
directory, the user has control over its access. Users can, in turn, belong to a group consisting of one
or more users who are given access to files and directories by their owners. In addition to granting
access to a group, an owner may also grant some set of access rights to everybody, which in Linux
terms is referred to as the world.
User accounts are defined in the /etc/passwd file and groups are defined in the /etc/group file.
When user accounts and groups are created, these files are modified along with /etc/shadow which
holds information about the user's password.
Option Explanation
-g Print only the effective group id
-G Print all Group ID’s
-n Prints name instead of number.
-r Prints real ID instead of numbers.
-u Prints only the effective user ID.
28
Access rights to files and directories are defined in terms of read access, write access, and execution
access. If we look at the output of the ls command, we can get some clue as to how this is
implemented:
The first ten characters of the listing are the file attributes. The first of these characters is the file
type. Here are the file types you are most likely to see:
The remaining nine characters of the file attributes, called the file mode, represent the read, write,
and execute permissions for the file's owner, the file's group owner, and everybody else.
For example: -rw-r--r- A regular file that is readable and writable by the file's owner. Members of
the file's owner group may read the file. The file is world-readable.
29
The ls command is used to read the permission of a file. In the following example, we have used ls
command with -l option to see the information about /etc/passwd file. Similarly, we can read the
current permissions of any file.
In the following example, we first go to the Desktop directory using cd command. In Desktop
directory, we create a text file “myfile.txt” using touch command and read its current permissions
using ls command.
Now, we change the permission of myfile.txt and set it to 777 that is everyone can read, write and
execute the file.
30
chmod also supports a symbolic notation for specifying file modes. Symbolic notation is divided into
three parts: who the change will affect, which operation will be performed, and what permission will
be set. To specify who is affected, a combination of the characters “u”, “g”, “o”, and “a” is used as
follows:
Character Meaning
u Owner
g Group
o Others
a all
If no character is specified, “all” will be assumed. The operation may be a “+” indicating that a
permission is to be added, a “-” indicating that a permission is to be taken away, or a “=” indicating
that only the specified permissions are to be applied and that all others are to be removed. For
example: u+x,go=rx Add execute permission for the owner and set the permissions for the group
and others to read and execute. Multiple specifications may be separated by commas.
In the following example, we change the permissions of myfile.txt using symbolic codes. As all of the
permissions of myfile.txt were set previously, now we make it readable only to the user while the
rest cannot read, write or execute the file.
On Unix-like operating systems, the umask command returns, or sets, the value of the system's file
mode creation mask. When user create a file or directory under Linux or UNIX, he/she creates it with
a default set of permissions. In most case the system defaults may be open or relaxed for file sharing
purpose.
umask command with no arguments can be used to return the current mask value. Similarly, If the
umask command is invoked with an octal argument, it will directly set the bits of the mask to that
argument.
31
The three rightmost octal digits address the "owner", "group" and "other" user classes respectively.
If fewer than 4 digits are entered, leading zeros are assumed. An error will result if the argument is
not a valid octal number or if it has more than 4 digits. If a fourth digit is present, the leftmost (high-
order) digit addresses three additional attributes, the setuid bit, the setgid bit and the sticky bit.
In the following example, we first read the current mask that is 0022 and then we created a file
myfile.txt using this mask and display its permission. Then we reset the mask with 111 and 333 octal
values and create new files. It can be seen clearly that new files are created with different default
permissions.
The su command is used to start a shell as another user. The command syntax looks like
this:
su -l username
32
On Unix-like operating systems, the sudo command ("superuser do", or "switch user, do")
allows a user with proper permissions to execute a command as another user, such as the
superuser.
Example: In the following example first, we created a new user “aliahmed” using adduser
command. Then we run the shell as aliahmed. In the end we logout using exit command.
Example: In the following example first, we created a file named myfile.txt as user ubuntu.
Then we changed the ownership of myfile.txt from ubuntu to aliahmed.
33
2. Package Management
Package Files
The basic unit of software in a packaging system is the package file. A package file is a
compressed collection of files that comprise the software package. A package may consist of
numerous programs and data files that support the programs. In addition to the files to be
installed, the package file also includes metadata about the package, such as a text
description of the package and its contents. Additionally, many packages contain pre- and
post-installation scripts that perform configuration tasks before and after the package
installation.
Repositories
While some software projects choose to perform their own packaging and distribution, most
packages today are created by the distribution vendors and interested third parties.
34
Packages are made available to the users of a distribution in central repositories that may
contain many thousands of packages, each specially built and maintained for the
distribution.
Dependencies
Programs seldom “standalone”; rather they rely on the presence of other software
components to get their work done. Common activities, such as input/output for example,
are handled by routines shared by many programs. These routines are stored in what are
called shared libraries, which provide essential services to more than one program. If a
package requires a shared resource such as a shared library, it is said to have a dependency.
Modern package management systems all provide some method of dependency resolution
to ensure that when a package is installed, all of its dependencies are installed too
Package management systems usually consist of two types of tools: low-level tools which
handle tasks such as installing and removing package files, and high-level tools that perform
metadata searching and dependency resolution. For Debian based systems low-level tools
are defined in dpkg while high-level tools are defined in apt-get, aptitude.
Example: To search apt repository for the emacs text editor, this command could be used:
dpkg-install package_file
35
Example: If the emacs-22.1-7.fc7-i386.deb package file had been downloaded from a non-
repository site, it would be installed this way:
The most common package management task is keeping the system up-to-date with the
latest packages. The high-level tools can perform this vital task in one single step.
Example: To apply any available updates to the installed packages on a Debian-style system:
Following command can be used to display a list of all the packages installed on the system:
$ apt list --installed
To list all software packages on Ubuntu Linux available for us, the following command can
be used:
$ apt list
These low-level tools can be used to display whether a specified package is installed:
36
Example:
dpkg --status emacs
If the name of an installed package is known, the following commands can be used to
display a description of the package:
Example:
apt -cache show emacs
2) Stage a1 (apply)
Lab Activities
Activity 1:
This activity is related to file permission. Perform the following tasks
1. Create a new directory named test in root directory as superuser
2. Make this directory public for all
3. Create a file “testfile.txt” in /test directory
4. Change its permissions that no boy can write the file, but the owner can read it.
5. Create another user “Usama”
6. Run the shell with user Usama
7. Try to read the “testfile.txt”
8. Logout as Usama
9. Change the permission of testfile.txt so that everyone can read, write and execute it
10. Run shell as Usama again
11. Now, read the file
Solution:
37
Activity 2:
Perform the following tasks
1. Set the permission such that a newly created file is readable only to the owner
2. Create a text file “act.txt” in /test directory crated in previous activity
3. Run the shell as user “usama” (created previously)
4. Access the file “act.txt”
5. Logout as usama
6. Now change the ownership of the file from ubuntu to usama
7. Run the shell again as usama
8. Read the file “act.txt” using cat command
9. Logout as usama
10. Now access the act.txt with user ubuntu
Solution:
38
Activity 3:
Perform the following tasks
1. search apt repository for the chromium browser
2. install the chromium browser using command line
3. write the command to update and upgrade the repository
4. list the software installed on your machine and write output on a file list.txt
5. read the list.txt file using cat command
39
3) Stage v (verify)
Home Activities:
familiar with adduser command using: man adduser/useradd, man groupadd useradd -
create a new user or update default new user information. Create 3 user accounts (user1,
user2, user3) and add 2 groups (gr1, gr2). add user1 to gr1 and add user2, user2 to gr2.
Check user ID (UID) and group ID (GID) by listing file /etc/passwd. Find lines with added
user. What is the UID and GID for these accounts? Write command which show UID and GID
for your user name:
2. create 3 files with touch command: files1, files2, files3.
3. Write the command line by using letters with chmod to set the following
permissions:
- rwxrwxr-x for file1
- r-x—x—x for file2
- ——xrwx for file3
4. Write the command line by using numbers with chmod to set the following
permissions:
- rwxrwxrwx for file4 (you have to prepare this file)
- -w------- for file5 (you have to prepare this file)
- rwx--x—x for folder1 (you have to prepare this folder)
5. Create two user accounts: tst1 and tst2 Logging in id: tst1, group users, with bash
shell, home directory /home/tst1 Logging in id: tst2, group public, with bash shell, home
directory home/tst2 For the two accounts set a password.
40
Logging in as tst1 and copy /bin/ls into tst1 home directory as myls file. Change the owner of
myls to tst1 and the permissions to 0710. What does this permission value mean?
Logging in as tst2 and try to use /home/tst1/myls to list your current directory. Does it work
?
Create a new group labo with tst1 and tst2. Change the owner group of myls file to labo. Try
again from tst2 account to execute /home/tst1/myls to list your current directory. Does it
work?
4) Stage a2 (assess)
Lab Assignment and Viva voce
LAB # 04
Statement of Purpose:
This lab will introduce the basic concept of Text Processing Tools and Basic System
Configuration Tools in Linux to you.
Activity Outcomes:
This lab teaches you the following topics:
Using Linux's graphical and text-based configuration tools to manage networking and
date/time settings
----------------------------------------------------------------------------------------------------------------
41
1) Stage J (Journey)
The wc (word count) command is used to display the number of lines, words, and bytes
42
Pipelines
The ability of commands to read data from standard input and send to standard output is
utilized by a shell feature called pipelines. Using the pipe operator “|” (vertical bar), the
standard output of one command can be piped into the standard input of another: For
example, we can use less to display, page-by-page, the output of any command that sends
its results to standard output:
$ls -l /usr/bin | less
Filters
Pipelines are often used to perform complex operations on data. It is possible to put several
commands together into a pipeline. Frequently, the commands used this way are referred
to as filters. Filters take input, change it somehow and then output it. The first one we will
try is sort.
Sort
Imagine we wanted to make a combined list of all of the executable programs in /bin and
/usr/bin, put them in sorted order and view it:
$ls /bin /usr/bin | sort | less
Since we specified two directories (/bin and /usr/bin), the output of ls would have
consisted of two sorted lists, one for each directory. By including sort in our pipeline,
we changed the data to produce a single, sorted list.
43
For example, find all the files in our list of programs that had the word “zip”
embedded in the name:
$ ls /bin /usr/bin | sort | grep zip
There are a couple of handy options for grep: “-i” which causes grep to ignore case
when performing the search (normally searches are case sensitive) and “-v” which tells grep
to only print lines that do not match the pattern.
Networking
There are number of commands that can be used to configure and control networking
including commands used to monitor networks and those used to transfer files. In this lab,
we will also see the above-mentioned commands. In addition, we are going to explore the
ssh program that is used to perform remote logins.
44
45
46
To change both the date and time, use the following syntax:
# timedatectl set-time YYYY-MM-DD HH:MM:SS
Where,
1. HH : An hour.
2. MM : A minute.
3. SS : A second, all typed in two-digit form.
4. YYYY: A four-digit year.
5. MM : A two-digit month.
6. DD: A two-digit day of the month.
For example, set the date ’23rd Nov 2015′ and time to ‘8:10:40 am’, enter:
# timedatectl set-time '2015-11-23 08:10:40'
# date
How do I set the current time only?
The syntax is:
# timedatectl set-time HH:MM:SS
# timedatectl set-time '10:42:43'
# date
Sample outputs:
Mon Nov 23 08:10:41 EST 2015
How do I set the time zone using timedatectl command?
To see list all available time zones, enter:
$ timedatectl list-timezones
$ timedatectl list-timezones | more
$ timedatectl list-timezones | grep -i asia
$ timedatectl list-timezones | grep America/New
To set the time zone to ‘Asia/Kolkata’, enter:
# timedatectl set-timezone 'Asia/Kolkata'
Verify it:
# timedatectl
Local time: Mon 2015-11-23 08:17:04 IST
Universal time: Mon 2015-11-23 02:47:04 UTC
47
2) Stage a1 (apply)
Activity 1:
This activity is related to file permission. Perform the following tasks
Solution:
0. Touch /test/testfile.txt
1. Less testfile.txt
2. wc testfile.txt
3. grep testfile.txt
4. head -n 3 testfile.txt
5. tail -n 3 testfile.txt
Activity 2:
Perform the following tasks
1. Find all the files with extension txt in the /test directory
2. Find the first line of the list of files in the /test directory
48
3. Find the last line of the list of files in the /test directory
4. Produce and view a single sorted list of files by combining two directories: /Desktop
and /bin
Solution
Activity 3:
Perform the following tasks
1. Examine the network using Ping command and view the performance statistics
Solution
1. ping localhost
3) Stage v (verify)
4) Stage a2 (assess)
Lab Assignment and Viva voce
49
LAB # 05
Statement of Purpose:
This lab will introduce the basic concepts related to process management through and
Writing C++ programs in Linux.
Activity Outcomes:
This lab teaches you the following topics:
50
1) Stage J (Journey)
The kernel maintains information about each process to help keep things organized. For
example, each process is assigned a number called a process ID or PID. PIDs are assigned in
ascending order, with init always getting PID 1. The kernel also keeps track of the memory
assigned to each process, as well as the processes' readiness to resume execution. Like files,
processes also have owners and user IDs, effective user IDs, etc. In the following, we will
discuss the most common commands; available in Linux to mange processes.
The most commonly used command to view processes is ps. This command displays the
processes for the current shell. We can use the ps command as given below
We can display all of the processes owned by the current user by using the x option.
51
Here, a new column is also added in the output that is STAT. This column shows the current
state of the process. The most common states are given below.
State Meaning
R Running
S Sleeping or waiting for an event such as keystroke
D Uninterruptible Sleep. Process is waiting for I/O such as a disk drive
T Stopped
Z A difunctional or zombie process
l multithreaded
s Session leader
+ Foreground process
< A high priority process
N A low priority process
Following are the most common option that can be used with ps command.
Option Description
-A or -e Display every active process on a Linux system
-x Display all of the processes owned by the user
-F Perform a full-format listing
-U Select by real user ID or name
-u Select by effective user ID or name
-p Select process by pid
-r Display only running processes
-L Show number of threads in a process
-G Show processes by Group
In the following example, we display processes that are related to the user ubuntu.
52
The top command is the traditional way to view your system’s resource usage and see the processes
that are taking up the most system resources. Top displays a list of processes, with the ones using
the most CPU at the top. An improved version of top command is htop but it is usually not pre-
installed in most distributions. When a top program is running, we can highlight the running
programs by pressing z. we can quit the top program by press q or Ctrl + c.
In the following example we display the dynamic view of the system process and resource usage.
Some of the basic options available with top commands are given below
Options Description
-u display specific User process details
-d To set the screen refresh frequency
53
The pstree command is used to display processes in tree-like structure showing the parent/child
relationships between processes.
A foreground process is any command or task you run directly and wait for it to complete. Unlike
with a foreground process, the shell does not have to wait for a background process to end before it
can run more processes. Normally, we start a program by entering its name in the CLI. However, if
we want to start a program in background, we will put an & after its name.
In the following example, first we open the gedit program normally as given below.
54
It can be noted that gedit is opened as foreground process and control does not returns to terminal
unless it is closed. Now, we start the gedit again as a background process.
It can be seen that after starting the gedit program control returns to the terminal and user can
interact with both terminal and gedit.
We can kill a process using the kill command. To kill a process, we provide the process id as an
argument (We could have also specified the process using a jobspec). In the following example, we
start the gedit program and then kill it using kill command.
The kill command doesn't exactly “kill” processes, rather it sends them signals. Signals are
one of several ways that the operating system communicates with programs. Programs, in
turn, “listen” for signals and may act upon them as they are received. Following are most
common signals that can be send with kill command.
Signal Meaning
INT INT Interrupt. Performs the same function as the Ctrl-c key sent from the
terminal. It will usually terminate a program.
TERM Terminate. This is the default signal sent by the kill command. If a program is
still “alive” enough to receive signals, it will terminate.
STOP Stop. This signal causes a process to pause without terminating.
CONT Continue. This will restore a process after a STOP signal.
Linux allows you to pause a running process rather than quitting or killing it. Pausing a
process just suspends all of its operation so it stops using any of your processor power even
while it still resides in memory. This may be useful when you want to run some sort of a
processor intensive task, but don't wish to completely terminate another process you may
have running. Pausing it would free up valuable processing time while you need it, and then
continue it afterwards.
We can paus a process by using kill command with STOP option. The process id is required
as an argument in kill command. In the following example, we start the gedit program in the
background. Then we find the pid of gedit using ps command and then; we pause the
process using kill command. Later, we can resume the process by using the kill command
with CONT option.
56
Every running process in Linux has a priority assigned to it. We can change the process
priority using nice and renice utility. Nice command will launch a process with a user defined
scheduling priority. Renice command will modify the scheduling priority of a running
process. In Linux system priorities are 0 to 139 in which 0 to 99 for real time and 100 to 139
for users. nice value range is -20 to +19 where -20 is highest, 0 default and +19 is lowest.
Relation between nice value and priority is:
PR = 20 + NI
So, the value of PR = 20 + (-20 to +19) is 0 to 39 that maps to 100-139.
In the following example, we start the gedit program in background and see its nice value using ps
command.
57
We can change the priority of a running process using renice command. In the following example,
we first start the gedit program in background. Then we change its priority using renice command.
We can also use the renice command to change the priority of all of the processes belonging to a
user or a group. In the following example, we change the nice value of all of the process belonging to
user ubuntu.
58
We next come to what are called high-level languages. They are called this since they enable
the developer to be less worried about the details of what the processor is doing and more
with taking care of the current issue. Programs written in high-level programming languages
are converted into machine language by processing them with another program, called a
compiler.
59
If g++ is not installed on your system; then it can be installed by writing the following commands
The above command will generate an executable file a.out. We can use -o option to specify the
output file name for the executable.
$ ./executable-file
In the following example, we write a simple C++ program that displays a Hello World
message and the then compile and execute this program using the above commands. To
write the program, we use the gedit text editor. The source code file is saved with .cpp
extension.
Open the gedit editor and pass the name of the file (hello.cpp) to be created
60
Now, close the source file and write the following command to compile hello.cpp
61
Here, argc variable will hold the number of arguments pass to the program while the argv
will contain pointers to those variables. argv[0] holds the name of the program while argv[1]
to argv[argc] hold the arguments. Command-line arguments are given after the name of the
program in command-line shell of Operating Systems. Each argument separated by a space.
If a space is included in the argument, then it is written in “”.
In the following example, we calculate the average of numbers; passed in the command-
line. Write the following code and save the file named as avg.cpp. Compile the avg.cpp and
create an executable file named avg and execute it. While writing the command to execute
avg pass the numbers whose average is required. It is shown below.
62
2) Stage a1 (apply)
Lab Activities
Activity 1:
This activity is related to process monitoring in Linux
1. Display all of the process in current shell
2. Display every active process in the system
3. Provide a full-format listing of process owned by you
4. Display a full-format listing of processes owned by user ubuntu
5. Display a process with id 1
6. Display the dynamic view of the current processes in the system and set the refresh
interval 0.5 second
7. Display the dynamic view of the processes owned by user with id 999 (or name
ubuntu)
8. Start the gedit program in background and then bring it foreground
9. Suspend the gedit program
10. Resume the gedit program
Solution:
1.
2.
63
3.
4.
5.
6.
7.
8.
9.
10.
Activity 2:
Perform the following tasks
64
Solution:
1.
2.
Activity 3:
Write a program in C++ that find the maximum and minimum number from an array.
Solution:
#include<iostream>
using namespace std;
int main ()
{
int arr[10], n, i, max, min;
cout << "Enter the size of the array : ";
cin >> n;
cout << "Enter the elements of the array : ";
for (i = 0; i < n; i++)
cin >> arr[i];
max = arr[0];
for (i = 0; i < n; i++)
{
if (max < arr[i])
max = arr[i];
}
min = arr[0];
for (i = 0; i < n; i++)
{
if (min > arr[i])
min = arr[i];
65
}
cout << "Largest element : " << max;
cout << "Smallest element : " << min;
return 0;
}
Activity 4:
Change the above program such that it accepts the input at command-line.
Solution:
#include<iostream>
#include<cstdlib>
using namespace std;
int main (int a_c, char *arr[ ])
{
int arr[10], n, i, max, min,cout,num;
count=a_c;
max = atoi(arr[1]);
for (i = 0; i < n; i++)
{
num=atoi(arr[i]);
if (max <num)
max = num;
}
min = atoi(arr[1]);
for (i = 0; i < n; i++)
{
num=atoi(arr[i]);
if (min > num)
min = num;
}
cout << "Largest element : " << max;
cout << "Smallest element : " << min;
return 0;
}
66
LAB # 06
Statement of Purpose:
This lab describes how a program can create, terminate, and control processes using system
calls. We will start with the some basic process creation commands and later will execute
complex process termination, and wait system calls. Moreover, you will learn how to create
orphans and zombie processes and how to replace one process with another during its
execution using exec( ).
Activity Outcomes:
This lab teaches you the following topics:
Instructor Note:
As pre-lab activity, introduce students to basic process creation using fork and exec.
67
1) Stage J (Journey)
Processes are organized hierarchically. Each process has a parent process, which explicitly arranged
to create it. The processes created by a given parent are called its child processes. A child inherits
many of its attributes from the parent process.
A process ID number names each process. A unique process ID is allocated to each process when it is
created. The lifetime of a process ends when its termination is reported to its parent process; at that
time, all of the process resources, including its process ID, are freed.
To monitor the state of your processes under Unix use the ps command:
ps [-option]
Used without options this produces a list of all the processes owned by you and associated with your
terminal.
These are some of the column headings displayed by the different versions of this command.
This PID is the process ID which you will b using to identify parent and child processes.
Process Identification:
The pid_t data type represents process IDs which is basically a signed integer type (int). You can get
the process ID of a process by calling:
getpid() - returns the process ID of the parent of the current process (the parent process ID).
getppid() - returns the process ID of the parent of the current process (the parent process ID).
Your program should include the header files ‘unistd.h’ and ‘sys/types.h’ to use these functions.
68
After forking a child process, both the parent and child processes continue to execute normally. If
you want your program to wait for a child process to finish executing before continuing, you must do
this explicitly after the fork operation, by calling wait () or waitpid (). These functions give you
limited information about why the child terminated--for example, its exit status code.
A newly forked child process continues to execute the same program as its parent process, at the
point where the fork call returns. You can use the return value from fork to tell whether the
program is running in the parent process or the child process.
When a child process terminates, its death is communicated to its parent so that the parent may
take some appropriate action. If the fork () operation is successful, there are then both parent and
child processes and both see fork return, but with different values: it returns a value of 0 in the child
process and returns the child's process ID in the parent process. If process creation failed, fork
returns a value of -1 in the parent process and no child is created.
#include <stdio.h>
#include <unistd.h> /* contains fork prototype */
int main(void)
{
printf("Hello World!\n");
fork( );
printf("I am after forking\n");
printf("\tI am process %d.\n", getpid( ));
}
gedit hello.c //write the above C code and close the editor
Output:
69
When this program is executed, it first prints Hello World! . When the fork is executed, an identical
process called the child is created. Then both the parent and the child process begin execution at the
next statement.
Note that:
2. The child process begins execution at the statement immediately after the fork, not at the
beginning of the program.
3. A parent process can be distinguished from the child process by examining the return value of the
fork call. Fork returns a zero to the child process and the process id of the child process to the
parent.
Example 2:
#include <stdio.h>
#include <unistd.h> /* contains fork prototype */
int main(void)
{
int pid;
printf("Hello World!\n");
printf("I am the parent process and pid is : %d .\n",getpid());
printf("Here i am before use of forking\n");
pid = fork();
printf("Here I am just after forking\n");
if (pid == 0)
printf("I am the child process and pid is :%d.\n",getpid());
else
printf("I am the parent process and pid is: %d .\n",getpid());
}
70
The above output shows that parent process is executed first and then child process is executed.
#include <stdio.h>
#include <unistd.h> /* contains fork prototype */
int main(void)
{
printf("Here I am just before first forking statement\n");
fork();
printf("Here I am just after first forking statement\n");
fork();
printf("Here I am just after second forking statement\n");
printf("\t\tHello World from process %d!\n", getpid());
}
Output:
71
Example 4:
Predict the output and verify after executing the following code
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
void forkexample()
{
// child process because return value zero
if (fork() == 0)
printf("Hello from Child!\n");
Output:
72
1. wait ():
A call to wait() blocks the calling process until one of its child processes exits or a signal is received.
After child process terminates, parent continues its execution after wait system call instruction.
Child process may terminate due to any of these:
It calls exit();
It receives a signal (from the OS or another process) whose default action is to terminate.
Wait () will force a parent process to wait for a child process to stop or terminate. Wait () return the
pid of the child or -1 for an error.
2. Exit ():
Exit () terminates the process which calls this function and returns the exit status value. Both UNIX
and C (forked) programs can read the exit status value.
By convention, a status of 0 means normal termination. Any other value indicates an error or
unusual occurrence.
Example 1:
#include<stdio.h>
#include<stdlib.h>
#include<sys/wait.h>
#include<unistd.h>
int main() {
pid_t cpid;
if (fork()== 0)
else
73
return 0;
Output:
Example 2:
#include<stdio.h>
#include<sys/wait.h>
#include<unistd.h>
int main()
if (fork()== 0)
else {
printf("Bye\n");
return 0;
Output:
74
3. Sleep ( ):
A process may suspend for a period of time using the sleep () command:
Orphan Process:
When a parent dies before its child, the child is automatically adopted by the original “init”
process whose PID is 1.
Zombie Process:
A process that terminates cannot leave the system until its parent accepts its return code. If its
parent process is already dead, it’ll already have been adopted by the “init” process, which
always accepts its children’s return codes (orphan). However, if a process’s parent is alive but
never executes a wait ( ), the process’s return code will never be accepted and the process will
remain a zombie.
Creation of orphan and zombie is left as an exercise for students in activities at the end of lab.
4. Ecec ( ):
The exec family of functions replaces the current running process with a new process. It can be
used to run a C program by using another C program. It comes under the header file unistd.h.
The program that the process is executing is called its process image. Starting execution of a
new program causes the process to forget all about its previous process image; when the new
program exits, the process exits too, instead of returning to the previous process image.
There are a lot of exec functions included in exec family of functions, for executing a file as a
process image e.g. execv(), execvp() etc. You can use these functions to make a child process
execute a new program after it has been forked. The functions in this family differ in how you
specify the arguments, but otherwise they all do the same thing.
Execv () :
Using this command, the created child process does not have to run the same program as the
parent process does. The exec type system calls allow a process to run any program files, which
include a binary executable or a shell script .
Syntax:
int execv (const char *file, char *const argv[]);
file: points to the file name associated with the file being executed.
argv: is a null terminated array of character pointers.
Example 1:
Let us see a small example to show how to use execv () function in C. We will have two .C files:
example.c and hello.c and we will replace the example.c with hello.c by calling execv() function
in example.c
75
Output:
76
2) Stage a1 (apply)
Lab Activities:
Activity 1:
In this activity, you are required to perform tasks given below:
Solution:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/wait.h>
int main()
{
int forkresult;
printf("%d: I am the parent. Remember my number!\n", getpid());
printf("%d: I am now going to fork ... \n", getpid());
forkresult = fork();
if (forkresult != 0)
{ /* the parent will execute this code */
printf("%d: My child's pid is %d\n", getpid(), forkresult);
}
else /* forkresult == 0 */
{ /* the child will execute this code */
printf("%d: Hi! I am the child.\n", getpid());
}
printf("%d: like father like son. \n", getpid());
return 0;
}
Activity 2:
1. Create a process and make it an orphan.
77
Hint: To, illustrate this insert a sleep statement into the child’s code. This ensured that the
parent process terminated before its child.
5. Now while child is sleeping parent will terminate. Print parent id of child to make sure it is
orphaned (PPID has been changed)
Solution:
#include <stdio.h>
main()
{
int pid ;
printf("I'am the original process with PID %d and PPID %d.\n",
getpid(), getppid()) ;
pid = fork ( ) ; /* Duplicate. Child and parent continue from here */
if ( pid != 0 ) /* pid is non-zero,so I must be the parent*/
{
printf("I'am the parent with PID %d and PPID %d.\n",
getpid(), getppid()) ;
printf("My child's PID is %d\n", pid ) ;
}
else /* pid is zero, so I must be the child */
{
sleep(4); /* make sure that the parent terminates first */
printf("I'm the child with PID %d and PPID %d.\n",
getpid(), getppid()) ;
}
printf ("PID %d terminates.\n", getpid()) ;
}
Output:
78
Activity 3:
Create a process and make it a Zombie.
Solution:
#include <stdio.h>
main ( )
{
int pid ;
pid = fork(); /* Duplicate. Child and parent continue from here */
if ( pid != 0 ) /* pid is non-zero, so I must be the parent */
{
while (1) /* Never terminate and never execute a wait ( ) */
sleep (100) ; /* stop executing for 100 seconds */
}
else /* pid is zero, so I must be the child */
{
exit (42) ; /* exit with any number */
}
}
79
Activity 4:
Write a C/C++ program in which a parent process creates a child process using a fork()
system call. The child process takes your age as input and parent process prints the age.
Solution:
Output:
80
Activity 5:
5. Write a C/C++ program that asks user to enter his name and his university name.
Within the same program, execute another program that asks the user to enter his
degree name and department name.
6. Hint: write 2 separate programs and execute using execv()
Solution:
Output:
3) Stage v (verify)
81
Home Activities:
Practice fork, exec, sleep and wait at home.
4) Stage a2 (assess)
Activity assessment and Viva voce at the end of lab.
82
LAB # 07
Statement Purpose:
This lab will explain to you the inter process communication through shared memory and
message passing in Linux.
Activity Outcomes:
This lab describes
Instructor Note:
As pre-lab activity, introduce students to the concept of inter-process communication
83
1) Stage J (Journey)
A process can be of two type:
Independent process.
Co-operating process.
An independent process is not affected by the execution of other processes while a co-
operating process can be affected by other executing processes. Though one can think that
those processes, which are running independently, will execute very efficiently but in
practical, there are many situations when co-operative nature can be utilized for increasing
computational speed, convenience and modularity. Inter process communication (IPC) is a
mechanism which allows processes to communicate each other and synchronize their
actions. The communication between these processes can be seen as a method of co-
operation between them. Processes can communicate with each other using these two
ways:
1. Shared Memory
2. Message passing
The Figure below shows a basic structure of communication between processes via shared
memory method and via message passing.
84
An operating system can implement both methods of communication. First, we will discuss
the shared memory method of communication and then message passing. Communication
between processes using shared memory requires processes to share some variable and it
completely depends on how programmer will implement it. One way of communication
using shared memory can be imagined like this: Suppose process1 and process2 are
executing simultaneously and they share some resources or use some information from
other process, process1 generate information about certain computations or resources
being used and keeps it as a record in shared memory. When process 2 need to use the
shared information, it will check in the record stored in shared memory and take note of the
information generated by process1 and act accordingly. Processes can use shared memory
for extracting information as a record from other process as well as for delivering any
specific information to other process.
There are two processes: Producer and Consumer. Producer produces some item and
Consumer consumes that item. The two processes shares a common space or memory
location known as buffer where the item produced by Producer is stored and from where
the Consumer consumes the item if needed. There are two version of this problem: first one
is known as unbounded buffer problem in which Producer can keep on producing items and
there is no limit on size of buffer, the second one is known as bounded buffer problem in
which producer can produce up to a certain amount of item and after that it starts waiting
for consumer to consume it. We will discuss the bounded buffer problem. First, the
Producer and the Consumer will share some common memory, then producer will start
producing items. If the total produced item is equal to the size of buffer, producer will wait
to get it consumed by the Consumer. Sim-
ilarly, the consumer first check for the availability of the item and if no item is available,
Consumer will wait for producer to produce it. If there are items available, consumer will
consume it. The pseudo code are given below:
85
86
In the above code, The producer will start producing again when the (free_index+1) mod
buff max will be free because if it it not free, this implies that there are still items that can
be consumed by the Consumer so there is no need to produce more. Similarly, if free index
and full index points to the same index, this implies that there are no item to consume.
Establish a communication link (if a link already exists, no need to establish it again.)
Start exchanging messages using basic primitives.
We need at least two primitives:
– send(message, destinaion) or send(message)
– receive(message, host) or receive(message)
87
The message size can be of fixed size or of variable size. if it is of fixed size, it is easy for OS
designer but complicated for programmer and if it is of variable size then it is easy for
programmer but complicated for the OS designer. A standard message can have two
parts: header and body.
The header part is used for storing Message type, destination id, source id, message length
and control information. The control information contains information like what to do if
runs out of buffer space, sequence number, priority. Generally, message is sent using FIFO
style.
Inter Process Communication through shared memory is a concept where two or more
process can access the common memory. And communication is done via this shared
memory where changes made by one process can be viewed by another process.
The problem with pipes, fifo and message queue – is that for two process to exchange
information. The information has to go through the kernel.
88
The client reads the data from the IPC channel again requiring the data to be copied
from kernel’s IPC buffer to the client’s buffer.
Finally the data is copied from the client’s buffer.
A total of four copies of data are required (2 read and 2 write). So, shared memory provides
a way by letting two or more processes share a memory segment. With Shared Memory the
data is only copied twice – from input file into shared memory and from shared memory to
the output file.
shmat(): Before you can use a shared memory segment, you have to attach yourself
to it using shmat(). void *shmat(int shmid ,void *shmaddr ,int shmflg);
shmid is shared memory id. shmaddr specifies specific address to use but we should set it to
zero and OS will automatically choose the address.
shmdt(): When you’re done with the shared memory segment, your program should
detach itself from it using shmdt(). int shmdt(void *shmaddr);
shmctl(): when you detach from shared memory,it is not destroyed. So, to destroy
shmctl() is used. shmctl(int shmid,IPC_RMID,NULL);
89
90
A message queue is a linked list of messages stored within the kernel and identified by a
message queue identifier. A new queue is created or an existing queue opened by msgget().
New messages are added to the end of a queue by msgsnd(). Every message has a positive
long integer type field, a non-negative length, and the actual data bytes (corresponding to
the length), all of which are specified to msgsnd() when the message is added to a queue.
Messages are fetched from a queue by msgrcv(). We don’t have to fetch the messages in a
first-in, first-out order. Instead, we can fetch messages based on their type field.
All processes can exchange information through access to a common system message
queue. The sending process places a message (via some (OS) message-passing module) onto
a queue which can be read by another process. Each message is given an identification or
type so that processes can select the appropriate message. Process must share a common
key in order to gain access to the queue in the first place.
msgget(): either returns the message queue identifier for a newly created message
queue or returns the identifiers for a queue which exists with the same key value.
91
92
93
2) Stage a1 (apply)
Lab Activities:
Solution:
Given a number ‘n’ and a n numbers, sort the numbers using Concurrent Merge Sort. (Hint:
Try to use shmget, shmat system calls).
Part1: The algorithm (HOW?)
Recursively make two child processes, one for the left half, one of the right half. If the
number of elements in the array for a process is less than 5, perform a Insertion Sort. The
parent of the two children then merges the result and returns back to the parent and so on.
But how do you make it concurrent?
The important part of the solution to this problem is not algorithmic, but to explain
concepts of Operating System and kernel.
To achieve concurrent sorting, we need a way to make two processes to work on the same
array at the same time. To make things easier Linux provides a lot of system calls via simple
API endpoints. Two of them are, shmget() (for shared memory allocation) and shmat() (for
shared memory operations). We create a shared memory space between the child process
that we fork. Each segment is split into left and right child which is sorted, the interesting
part being they are working concurrently! The shmget() requests the kernel to allocate
a shared page for both the processes.
94
95
96
97
98
3) Stage v (verify)
Home Activities:
Practice the Linux commands discussed in the lab.
4) Stage a2 (assess)
Activity assessment and Viva voce at the end of lab.
99
LAB # 08
Statement Purpose:
This lab will give you’ll implement multithreading in C++ language using POSIX library,
Activity Outcomes:
The primary objective of this lab is to implement the Thread Management Functions:
Creating Threads
Terminating Thread Execution
Passing Arguments to Threads
Thread Identifiers
Joining Threads
Detaching / Undetaching Threads
Peterson’s solution using threads
Instructor Note:
https://www.geeksforgeeks.org/multithreading-in-cpp/
https://www.geeksforgeeks.org/petersons-algorithm-for-mutual-exclusion-set-2-cpu-cycles-and-
memory-fence/
100
1) Stage J (Journey)
Introduction
Multitasking is the feature that allows your computer to run two or more programs
concurrently and Multithreading is a specialized form of multitasking. In general, there are
two types of multitasking: process-based and thread-based.
A multithreaded program contains two or more parts that can run concurrently. Each part of
such a program is called a thread, and each thread defines a separate path of execution. A
thread is a semi-process, that has its own stack, and executes a given piece of code. Unlike a
real process, the thread normally shares its memory with other threads (where as for
processes we usually have a different memory area for each one of them). A Thread Group
is a set of threads all executing inside the same process. They all share the same memory,
and thus can access the same global variables, same heap memory, same set of file
descriptors, etc. All these threads execute in parallel (i.e. using time slices, or if the system
has several processors, then really in parallel).
C++ does not contain any built-in support for multithreaded applications. Instead, it relies
entirely upon the operating system to provide this feature.
What are pthreads? Historically, hardware vendors have implemented their own
proprietary versions of threads. These implementations differed substantially from each
other making it difficult for programmers to develop portable threaded applications.
Pthreads are defined as a set of C language programming types and procedure calls.
Vendors usually provide a Pthreads implementation in the form of a header/include file and
a library, which you link with your program.
In this lab we are going to write multi-threaded C++ program using POSIX. POSIX Threads, or
Pthreads provides API which are available on many Unix-like POSIX systems such as
FreeBSD, NetBSD, GNU/Linux, Mac OS X and Solaris.
2) Stage a1 (apply)
Lab Activities:
Creating Threads
101
1 Thread
An unique identifier for the new thread returned by the subroutine.
2 Attr
An opaque attribute object that may be used to set thread attributes. You can specify
a thread attributes object, or NULL for the default values.
3 start_routine
The C++ routine that the thread will execute once it is created.
4 Arg
A single argument that may be passed to start_routine. It must be passed by
reference as a pointer cast of type void. NULL may be used if no argument is to be
passed.
The maximum number of threads that may be created by a process is implementation
dependent. Once created, threads are peers, and may create other threads. There is no
implied hierarchy or dependency between threads.
Terminating Threads
#include <pthread.h>
pthread_exit (status)
Here pthread_exit is used to explicitly exit a thread. Typically, the pthread_exit routine is
called after a thread has completed its work and is no longer required to exist.
If main finishes before the threads it has created, and exits with pthread_exit, the other
threads will continue to execute. Otherwise, they will be automatically terminated when
main finishes.
Activity 1:
Write a program in C++ to create and terminate threads.
102
This simple example code creates 5 threads with the pthread_create routine. Each thread
prints a "Hello World!" message, and then terminates with a call to pthread_exit.
#include <iostream>
#include <cstdlib>
#include <pthread.h>
#define NUM_THREADS 5
int main () {
pthread_t threads[NUM_THREADS];
int rc;
int i;
if (rc) {
cout << "Error:unable to create thread," << rc << endl;
exit(-1);
}
}
pthread_exit(NULL);
}
103
Activity 2:
Passing Arguments to Threads
This example shows how to pass multiple arguments via a structure. You can pass any
data type in a thread callback because it points to void as explained in the following
example
#include <iostream>
#include <cstdlib>
#include <pthread.h>
#define NUM_THREADS 5
struct thread_data {
int thread_id;
char *message;
};
pthread_exit(NULL);
}
int main () {
pthread_t threads[NUM_THREADS];
struct thread_data td[NUM_THREADS];
int rc;
int i;
if (rc) {
cout << "Error:unable to create thread," << rc << endl;
exit(-1);
}
}
pthread_exit(NULL);
104
When the above code is compiled and executed, it produces the following result −
main() : creating thread, 0
main() : creating thread, 1
main() : creating thread, 2
main() : creating thread, 3
main() : creating thread, 4
Thread ID : 3 Message : This is message
Thread ID : 2 Message : This is message
Thread ID : 0 Message : This is message
Thread ID : 1 Message : This is message
Thread ID : 4 Message : This is message
Activity 3:
Joining and Detaching Threads
There are following two routines which we can use to join or detach threads −
The pthread_join subroutine blocks the calling thread until the specified threadid thread
terminates. When a thread is created, one of its attributes defines whether it is joinable or
detached. Only threads that are created as joinable can be joined. If a thread is created as
detached, it can never be joined.
This example demonstrates how to wait for thread completions by using the Pthread join
routine.
#include <iostream>
#include <cstdlib>
#include <pthread.h>
#include <unistd.h>
#define NUM_THREADS 5
tid = (long)t;
105
sleep(1);
cout << "Sleeping in thread " << endl;
cout << "Thread with id : " << tid << " ...exiting " << endl;
pthread_exit(NULL);
}
int main () {
int rc;
int i;
pthread_t threads[NUM_THREADS];
pthread_attr_t attr;
void *status;
if (rc) {
cout << "Error:unable to create thread," << rc << endl;
exit(-1);
}
}
106
When the above code is compiled and executed, it produces the following result −
Activity 4
Peterson solution for 2 processes critical section problem
#include<pthread.h>
#include<stdio.h>
void *func1(void *);
107
value of i in func2 is 0
value of global in func2 is 25
108
value of i in func2 is 1
value of global in func2 is -50
value of global in func1 is 50
value of global in func1 is 150
This solution do not guarantee mutual exclusion between the two process. The code in
earlier Activity 4 might have worked on most systems, but is was not 100% correct. The logic
was perfect, but most modern CPUs employ performance optimizations that can result in
out-of-order execution. This reordering of memory operations (loads and stores) normally
goes unnoticed within a single thread of execution, but can cause unpredictable behaviour
in concurrent programs. When a thread was waiting for its turn, it ended in a long while
loop which tested the condition millions of times per second thus doing unnecessary
computation. There is a better way to wait, and it is known as “yield”.
In above activity the compiler considers the following 2 statements as independent of each
other and thus tries to increase the code efficiency by re-ordering them, which can lead to
problems for concurrent programs.
while (f = = 0);
print x;
To avoid this we place a memory fence to give hint to the compiler about the possible
relationship between the statements across the barrier.
#include<pthread.h>
#include<stdio.h>
void *func1(void *);
void *func2(void *);
int flag[2];
int turn=0;
int global=100;
int main()
{
pthread_t tid1,tid2;
pthread_create(&tid1,NULL,func1,NULL);
pthread_create(&tid2,NULL,func2,NULL);
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
}
109
{
int i=0;
while(i<2)
{
flag[0]=1;
turn=1;
__sync_synchronize();
while(flag[1]==1 && turn==1) sched_yield();
global+=100;
// printf("FT: g: %d",global);
// printf("value of i in func1 is %d \n",i);
printf("value of global in func1 is %d \n",global);
flag[0]=0;
i++;
}
}
void *func2(void *param)
{
int i=0;
while(i<2)
{
flag[1]=1;
turn=0;
__sync_synchronize();
while(flag[0]==1 && turn==0)sched_yield();
global-=75;
// printf("SP: g: %d",global);
printf("value of i in func2 is %d \n",i);
printf("value of global in func2 is %d \n",global);
flag[1]=0;
i++;
}
}
3) Stage v (verify)
Home Activities:
1. Write a program that uses multiple threads to find which integer between 1 and
100,000 has the largest number of divisors, and how many divisors does it have?.
By using threads, your program will take less time to do the computation when it is
run on a multiprocessor computer. At the end of the program, output the elapsed
time, the integer that has the largest number of divisors, and the number of
divisors that it has.
110
3) Stage v (verify)
Home Activities:
1) Practice the shell functions discussed in the lab
4) Stage a2 (assess)
Activity assessment and Viva voce at the end of lab.
111
LAB # 09
Statement Purpose:
This lab will give you’ll implement Process synchronization (i.e. Mutex and
Semaphores) in C++ language using threads.
Activity Outcomes:
The primary objective of this lab is to implement the process synchronization by:
Creating/Destroying Mutexes
Locking/Unlocking Mutexes
Using Semaphores
112
1) Stage J (Journey)
Introduction
When multiple threads are running they will invariably need to communicate with each other in
order synchronize their execution. One main benefit of using threads is the ease of using
synchronization facilities.
Threads need to synchronize their activities to effectively interact. This includes:
Implicit communication through the modification of shared data
Explicit communication by informing each other of events that have occurred.
This lab describes the synchronization types available with threads and discusses when and how to
use synchronization. There are a few possible methods of synchronizing threads and here we will
discuss:
1. Mutual Exclusion (Mutex) Locks
2. Semaphores
If threads execute this code independently it will lead to garbage. The access to the
common_variable by both of them simultaneously is prevented by having a lock, performing the
thing and then releasing the lock.
1. Mutexes
Mutual exclusion locks (mutexes) can prevent data inconsistencies due to race conditions. A race
condition often occurs when two or more threads need to perform operations on the same memory
area, but the results of computations depends on the order in which these operations are
performed.
Mutex Variables:
Mutex is a shortened form of the words "mutual exclusion". Mutex variables are one of the primary
means of implementing thread synchronization. A mutex variable acts like a "lock" protecting access
to a shared data resource. The basic concept of a mutex as used in Pthreads is that only one thread
can lock (or own) a mutex variable at any given time. Thus, even if several threads try to lock a
mutex only one thread will be successful. No other thread can own that mutex until the owning
thread unlocks that mutex. Threads must "take turns" accessing protected data.
Very often the action performed by a thread owning a mutex is the updating of global variables. This
is a safe way to ensure that when several threads update the same variable, the final value is the
same as what it would be if only one thread performed the update. The variables being updated
belong to a "critical section".
A typical sequence in the use of a mutex is as follows:
113
When several threads compete for a mutex, the losers block at that call an unblocking call is
available with "trylock" instead of the "lock" call.
Mutex variables must be of type pthread_mutex_t. The attr object is used to establish properties for
the mutex object, and must be of type pthread_mutexattr_t if used (may be specified as NULL to
accept defaults). If implemented, the pthread_mutexattr_init( ) and pthread_mutexattr_destroy( )
routines are used to create and destroy mutex attribute objects respectively.
pthread_mutex_destroy( ) should be used to free a mutex object which is no longer needed.
pthread_mutex_trylock( ) will attempt to lock a mutex. However, if the mutex is already locked,
the routine will return immediately. This routine may be useful in preventing deadlock
conditions, as in a priority-inversion situation.
Mutex contention: when more than one thread is waiting for a locked mutex, which thread will
be granted the lock first after it is released? Unless thread priority scheduling (not covered) is
used, the assignment will be left to the native system scheduler and may appear to be more or
less random. pthread_mutex_unlock( ) will unlock a mutex if called by the owning thread.
Calling this routine is required after a thread has completed its use of protected data if other
threads are to acquire the mutex for their work with the protected data.
An error will be returned:
If the mutex was already unlocked
114
2. Semaphores
Semaphore is another tool to synchronize activities in a computer. The concept of semaphores
as used in computer synchronization is due to the Dutch computer scientist Edsgar Dijkstra.
They have the advantages of being very simple, but sufficient to construct just about any other
synchronization function you would care to have.
There are several versions to implement semaphores. The most common versions are:
1) POSIX semaphores
2) System V IPC semaphores
This lab will consider only POSIX semaphore, since POSIX semaphores has very clear API
functions to perform semaphore operations. However, it is more efficient to use System V
semaphore than POSIX semaphore when semaphores are shared between processes.
What is a Semaphore?
A semaphore is an integer variable with two atomic operations:
1) wait. Other names for wait are P, down and lock.
2) signal: Other names for signal are V, up, unlock and post.
The simplest way to understand semaphore is, of course, with code. Here is a little pseudo-code
that may help.
Example 1 (Signaling)
115
This example represents the simplest use for a semaphore (which is signaling), in which one
process/thread sends a signal to another process/thread to indicate that something has happened.
Suppose process one must execute statement a before process two executes statement b. To solve
this synchronization problem, we need a semaphore (say sync) with initial value 0, and that both
processes have shared access to it. The following pseudo-code describes the solutions:
Example 2 (Rendezvous)
Puzzle: Generalize the signal pattern so that it works both ways. Process One has to wait for Process
Two and vice versa. In other words, given this code.
we want to guarantee that a1 happens before b2 and b1 happens before a2. Please try to think how
to solve this puzzle before proceeding to next paragraph.
Hint: You need to use two semaphores.
While working on the previous problem, you might have tried something like this :
if so, I hope you will reject it quickly because it has serious problem of Deadlock! Solutions for this
problem are:
Solution 1:
116
Solution 2:
This solution is probably less efficient, since it might have to switch between process One and Two
more than necessary.
POSIX Semaphore
Semaphores are part of the POSIX.1b standard adopted in 1993. The POSIX.1b standard defines two
types of semaphores: named and unnamed. A POSIX.1b unnamed semaphore can be used by a single
process or by children of the process that created them. A POSIX.1b named semaphore can be used
by any processes. In this section, we will consider only how to initialize unnamed semaphore.
The following header summarizes how we can use POSIX.1b unnamed semaphore:
117
Lab Activities
Activity 1.a:
This simple example code demonstrates the use of several Pthread mutex routines. The serial
version may be reviewed first to compare how the threaded version performs the same task.
#include <stdio.h>
#include <pthread.h>
/* The function run when the thread is created */
void* compute_thread (void*);
main( )
{
/* This is data describing the thread created */
pthread_t tid; /* thread ID structure */
pthread_attr_t attr; /* thread attributes */
char hello[ ] = {"Hello, "}; /* some typical data */
char thread[ ] = {"thread"};
/* Initialize the thread attribute structure */
pthread_attr_init(&attr);
/* Create another thread. ID is returned in &tid */
/* The last parameter passed to the thread function */
pthread_create(&tid, &attr, compute_thread, thread);
/* Continue on with the base thread */
printf(hello);
sleep(1);
printf("\n");
exit(0);
}
/* The thread function to be run */
118
Hello, thread
After creating a new thread, main process prints “Hello, ” and then sleeps. The new thread
then prints “thread”.
Activity 1.b:
This example shows how to pass multiple arguments via a structure. You can pass any data
type in a thread callback because it points to void as explained in the following example
#include <pthread.h>
#include <stdio.h>
/* Function run when the thread is created */
void* compute_thread (void*);
/* This is the lock for thread synchronization */
pthread_mutex_t my_sync;
main( )
{
/* This is data describing the thread created */
pthread_t tid;
pthread_attr_t attr;
char hello[ ] = {"Hello, "};
char thread[ ] = {"thread"};
/* Initialize the thread attributes */
pthread_attr_init (&attr);
/* Initialize the mutex (default attributes) */
pthread_mutex_init (&my_sync,NULL);
/* Create another thread. ID is returned in &tid */
/* The last parameter is passed to the thread function */
/* Note reversed the order of "hello" and "thread" */
pthread_create(&tid, &attr, compute_thread, hello);
sleep(1); /* Let the thread get started */
/* Lock the mutex when it's our turn to do work */
pthread_mutex_lock(&my_sync);
printf(thread);
printf("\n");
pthread_mutex_unlock(&my_sync);
exit(0);
}
/* The thread function to be run */
119
Hello, thread
The main process sleeps after creating new thread which prints “Hello, ”. After waking up,
the main process prints “thread”. Printf is treated as Critical Section and hence guarded with
Mutex Lock so that no two process can print at the same time.
Activity 2:
Semaphores (Signaling):
Lab1.c #include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
/* Global variables */
int x = 0;
sem_t sync;
/* Thread function */
void *my_func(void *arg)
{
/* wait for signal from main thread */
sem_wait(&sync);
printf("X = %d\n", x);
}
void main ()
{
pthread_t thread;
/* semaphore sync should be initialized by 0 */
if (sem_init(&sync, 0, 0) == -1) {
perror("Could not initialize mylock semaphore");
exit(2);
}
if (pthread_create(&thread, NULL, my_func, NULL) < 0) {
perror("Error: thread cannot be created");
exit(1);
}
120
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
//using namespace std;
sem_t lock; //lock is defined as semaphore
//routine for thread 1
void *thread1(void *varg)
{
sem_wait(&lock);
printf("this from Thread 1\n"); // CS
sem_post(&lock);
return NULL;
}
//routine for thread 2
void *thread2(void *varg)
{
sem_wait(&lock);
printf("this from Thread 2\n"); //CS
sem_post(&lock);
return NULL;
}
int main()
{
sem_init(&lock,0,1); // lock is initialized as 1 with last argument. middle argument is for threads(i.e. 1 for
processes and 0 for threads)
pthread_t t1, t2;
printf("Before Thread\n");
pthread_create(&t1, NULL, thread1,NULL );
pthread_create(&t2, NULL, thread2,NULL );
pthread_join(t1, NULL);
pthread_join(t2, NULL);
121
printf("After Thread\n");
return 0;
}
122
2) Stage v (verify)
Home Activities:
Practice the shell functions discussed in the lab
4) Stage a2 (assess)
Activity assessment and Viva voce at the end of lab.
123
LAB # 10
Statement Purpose:
This lab will give you’ll implement Filing in C++ language.
Activity Outcomes:
The primary objective of this lab is to implement the Filing in C++ language.
1) Stage J (Journey)
Introduction
A process is a currently executing instance of a program. All programs by default execute in the user
mode. A C program can invoke UNIX system calls directly. A system call can be defined as a request
to the operating system to do something on behalf of the program. During the execution of a
system call, the mode is change from user mode to kernel mode (or system mode) to allow the
execution of the system call. The kernel, the core of the operating system program in fact has
control over everything. All OS software is trusted and executed without any further verification. All
other software needs to request kernel mode using specific system calls to create new processes
and manage I/O. A high level programmer does not have to worry about the mode change from
user-mode to kernel-mode as it is handled by a predefined library of system calls. Unlike processes
in user mode, which can be replaced by another process at any time, a process in kernel mode
cannot be arbitrarily replaced by another process. A process in kernel mode can only be suspended
by an interrupt or exception. A C system call software instruction generates an OS interrupt
commonly called the operating system trap. The system call interface handles these interruptions in
a special way. The C library function passes a unique number corresponding to the system call to the
kernel, so kernel can determine the specific system call user is invoking. After executing the kernel
command the operating system trap is released and the system returns to user mode. Unix system
calls are primarily used to manage the file system or control processes or to provide communication
between multiple processes. A subset of the system calls include
124
System calls interface often change and therefore it is advisable to place system calls in subroutines
so subroutines can be adjusted in the event of a system call interface change. When a system call
causes an error, it returns -1 and store the error number in a variable called “errno” given in a
header file called /usr/include/errno.h. When a system call returns an error, the function perror can
be used to print a diagnostic message. If we call perror( ), then it displays the argument string, a
colon, and then the error message, as directed by "errno", followed by a newline.
if (unlink("text.txt")==-1){ perror(""); } If the file text.txt does not exists, unlink will return
-1 and that in return will cause the program to print the message “File does not exists”
File structure related system calls to manage the file system are quite common. Using file structure
related system calls, we can create, open, close, read, write, remove and alias, set permission, get
file information among other things. The arguments to these functions include either the relative or
absolute path of the file or a descriptor that defines the IO channel for the file. A channel provides
access to the file as an unformatted stream of bytes. We will now look at some of the file related
functions provided as system calls.
The high level library functions given by <stdio.h> provide most common input and output
operations. These high level functions are built on the top of low-level structures and calls provided
by the operating system. In this section, we will look at some low level I/O facilities that will provide
insight into how low level I/O facilities are handled and therefore may provide ways to use I/O in
ways that are not provided by the stdio.h. In UNIX, I/O hardware devices are represented as special
files. Input/Output to files or special files (such as terminal or printers) are handled the same way.
UNIX also supports “pipes” a mechanism for input/output between processes. Although pipes and
files are different I/O objects, both are supported by low level I/O mechanisms.
A file can be created using the creat function as given by the following prototype.
125
/usr/include/sys/stat.h
For example, to create a file with read and write access only to user, we can do the following.
creat(“myfile”, S_IREAD | S_IWRITE);
The above code opens the filename for reading or writing as specified by the access and returns an
integer descriptor for that file. Descriptor is an integer (usually less than 16) that indicates a table
entry for the file reference for the current process. The stdin(0), stdout(1) and stderr(3) are given.
Other files will be provided with the next available descriptor when opening. File name can be given
126
as full path name, relative path name, or simple file name. If the file does not exist, then open
creates the file with the given name. Let us take a detail look at the arguments to open.
filename : A string that represents the absolute, relative or filename of the file
flags : An integer code describing the access (see below for details)
mode : The file protection mode usually given by 9 bits indicating rwx permission
O_CREAT bit is on and file exists If the open call fails, a -1 is returned; otherwise a descriptor is
returned. For example, to open a file for read and truncates the size to zero we could use,
We assume that the file exists and note that zero can be used for protection mode. For opening files,
the third argument can always be left at 0.
Reading and writing a file is normally sequential. For each open file, a current position points to the
next byte to be read or written. The current position can be movable for an actual file, but not for
stdin when connected to a keyboard.
fd is the file descriptor, buffer is address of a memory area into which the data is read and bytes is
the maximum amount of data to read from the stream. The return value is the actual amount of
data read from the file. The pointer is incremented by the amount of data read. Bytes should not
exceed the size of the buffer. Write System Call The write system call is used to write data to a file or
other object identified by a file descriptor. The prototype is #include <sys/types.h> size_t
write(int fd, char *buffer, size_t bytes); fd is the file descriptor, buffer is the address of the area of
127
memory that data is to be written out, bytes is the amount of data to copy. The return value is the
actual amount of data written, if this differs from bytes then something may be wrong.
Example: Consider the C high level function readline(char [], int) that reads a line from stdin and
store the line in a character array. This function can now be rewritten using low level read as follows
char* tmp = s;
*tmp = '\0';
return (tmp-s);
include <unistd.h>
When a process terminates, all the files associated with the process are closed. But it is always a
good idea to close a file as they do consume resources and systems impose limits on the number of
files a process can keep open.
Whenever a read() or write() operation is performed on a file, the position in the file at which
reading or writing starts is determined by the current value of the read/write pointer. The value of
the read/write pointer is often called the offset. It is always measured in bytes from the start of the
file. The lseek() system call allows programs to manipulate this directly by providing the facility for
direct access to any part of the file. In other words, the lseek allows random access to any byte of
the file. It has three parameters and the prototype is
#include <sys/types.h>
origin position
1 Current position
128
Call Meaning
creat(filename, mode);
The mode can be selected from the following octal bit patterns
The link( ) function creates an alias name file2 for file1, that exists in the current directory. Use of
unlink with the original file name will remove the file.
Directories can be created and removed using mkdir and rmdir function calls. The function
prototypes are
For example, creating a new directory called “newfiles” with only the READ access for the user we
can do the following.
mkdir(“newfiles”, 0400);
129
rmdir(“newfiles”);
Caution: Be very careful about removing directories. These are system calls that are executed w/o
further confirmation. You can also reset the file/dir permission with chmod function. The prototype
is given by
#include <sys/types.h>
#include <sys/stat.h>
For example, the directory that was created above called “newfiles” has only read access on the
owner. But if you decided to change the read access from owner to all groups, then you can call:
chmod(“newfiles”, 0444);
Accessing Directories
A UNIX directory contains a set of files that can be accessed using the sys/dir.h library. We include
the library with
#include <sys/dir.h>
Opens a directory given by dir_name and provides a pointer to access files within the directory. The
open DIR stream can be used to access a struct that contains the file information. The function
returns a pointer to the next entry in the directory. A NULL pointer is returned when the end of the
directory is reached. The struct direct has the following format.
struct dirent {
Using system libraries, we can write our own “find” function for example. The following function,
search (char* file, char* dir) returns 0 if the file is found in the directory and returns 1 otherwise.
#include <string.h>
#include <sys/types.h>
#include <sys/dir.h>
130
DIR *dirptr=opendir(dir);
entry = readdir(dirptr); }
Status of a file such as file type, protection mode, time when the file was last modified can be
accessed using stat and fstat functions. The prototypes of stat and fstat functions are
stat and fstat functions are equivalent except that former takes the name of a file, while the latter
takes a file descriptor. For example, we can get the status of a file as follows.
The status of the file that is retrieved and placed in the buf has many information about the file. For
example, the stat structure contains useful information such as
Example
#include <sys/types.h>
#include <sys/stat.h>
#include <dirent.h>
131
char dirpath[256];
getcwd(dirpath,256);
for (dp=readdir(dir);
dp != NULL ;
dp=readdir(dir)){
stat(dp->d_name, &statbuf);
3)Stage v (verify)
Home Activities:
Practice the shell functions discussed in the lab
4) Stage a2 (assess)
Activity assessment and Viva voce at the end of lab.
132
LAB # 11
Statement Purpose:
This lab will explain to you the basic concept of shell and shell scripting in Linux.
Activity Outcomes:
This lab describes
Instructor Note:
As pre-lab activity, introduce students to the concept of shell
133
1) Stage J (Journey)
1. Shell
A shell is simply a program which is used to start other programs. It takes the commands
from the keyboard and gives them to the operating system to perform the particular task.
There are many different shells, but all derive several of their features from the Bourne
shell, a standard shell developed at Bell Labs for early versions of Unix. Linux uses an
enhanced version of the Bourne shell called bash or the “Bourne-again” shell. The bash shell
is the default shell on most Linux distributions, and /bin/sh is normally a link to bash on a
Linux system.
Shell is an Interface between the user and the operating system.
Bourne, Korn, C Shell, tcsh, bash, zsh, etc. are different UNIX Shells
Recommended — Korn (ksh) Shell
o ksh is a variant of the Bourne Shell.
o Provides all features of the Bourne Shell.
o Allows access to prior (history) commands with the j, k keys (after <escape>).
Changing Shells: chsh command allows users to switch default login shells.
History is a mechanism for saving recently executed commands (events).
o export HISTSIZE = 25 : command to save the last 25 commands.
o history : command to display the history list.
o r 3 : executes command number 3 in the history list.
o r : re-executes the last executed command.
o r prog: re-executes the most recent command beginning with the string
"prog".
2. Shell scripting
If the shell offers the facility to read its commands from a text file ,then its syntax and
features may be thought of as a programming language, and such files may be thought of as
scripts. So, a shell is actually two things:
1. An interface between user and OS.
134
2. A programming language.
Shell Script is series of commands written in plain text file the shell reads the commands
from the file just as it would have typed them into a terminal. The basic advantage of shell
scripting includes:
1. Shell script can take input from user, file and output them on screen.
2. Useful to create our own commands.
3. Save lots of time.
4. To automate some task of day today life.
5. System Administration part can be also automated.
A shell script (or shell program) is a series of Unix commands placed in an ASCII text file.
Each shell (ksh/csh/sh..) provides mechanisms for control (e.g. statements like if, while,
for, etc).
Unix commands + shell variables + control mechanisms = powerful programming
language.
135
Use any editor (gedit etc) to write shell script. Then save the shell script to a directory
and name it intro. Shell scripts don’t need a special file extension, so leave the extension
blank (or you can add the extension .sh).
2.2 Example
2.3 Example
Creating a simple shell script (you could do this with emacs):
$ cat > gohome
#!/usr/local/bin/ksh
cd ~
ls -F
^D
Change file permissions: $ chmod a+x gohome
Run it: $ gohome
136
System defined variables are already defined and included in the environment when we
login. Their names are in upper case letters. Some of them are as follows:
HISTFILE – filename of the history file. Default is $HOME/.sh_history.
HISTSIZE – Maximum number of commands retained in the history file
HOME – The pathname of your home directory
IFS – Inter Filed Separator. Zero or more characters treated by the shell as delimiters in
parsing a command line into words. Default – Blank, Tab and Newline in succession
PATH – List of directories separated by colon that are searched for executables
PS1 – It is the primary prompt string. Korn Shell performs a full substitution of the value of
PS1 before displaying it at the beginning of each command input line.
PS2 – Secondary prompt string. It is displayed when command is continued on the next line
PS3 – The value of this string is printed at the selection prompt by the select command
PS4 – The value of this string is printed in front of each line by the trace or the -x option
PWD – The present working directory
RANDOM – This is a random number from 0 – 32767. Its value will be different every time
you examine it.
SHELL – The pathname of the shell
SECONDS – The number of seconds since the ksh was invoked
TERM – This is an alphanumeric string that identifies the type of your terminal. Its proper
setting is imperative to the proper functioning of your terminal.
TMOUT–An integer specifying the number of seconds after which no terminal activity
should cause the Korn Shell to log you out
USER – Your login name
$0 – The name of the shell script
$# – The number of parameters passed
$$ – The PID of the parent process i.e. shell
$? – exit status of last command run
Parameter variables contain the values of the parameters passed to a shell script.
$1, $2,… Store the parameters given to the script
$* A list of all parameters, separated by the character defined in IFS
$@ Same as $* except the parameters are separated by space character
User defined variables are subject to the following rules:
Rules:
137
–Variable names can begin with a letter or an underscore and can contain an arbitrary
number of letters, digits and underscores that is it can have any name of the form [A-Za-
z][A-Za-z0-9_]*.
–No arbitrary upper limit to the variables you can define or use
–A variable retains its value from the time it is set – whether explicitly by you or implicitly by
the shell – until its value is changed or the shell exits
–The variable is not passed to commands / shell scripts that you invoke unless it is exported
Note: You can assign values to variables and export them to pass variables downward to
subshells of your current shells, but you cannot pass values upward to the higher-level shells
or shell scripts
For ksh:
o variable=value
Notice that there are no spaces on either side of the equals sign.
o export variable=value
Using export makes the value visible to child processes.
138
You can use the built-in variable $? to access the exit status of the previously run
command. If the above script were HelloScript:
$ HelloScript;print $?
0
CDPATH=$HOME
PATH=.:./bin:$HOME/bin:/bin:/sbin:/usr/bin:/usr/sbin:/usr/ucb:\
/usr/local/bin:/usr/bin/X11
EDITOR=/usr/ucb/vi
ENV=$HOME/.kshrc
EXINIT='set ai nonumber showmatch wrapmargin=72 nowrapscan'
139
FCEDIT=/usr/ucb/vi
HISTSIZE=32
MAIL=/usr/spool/mail/$USER
PS1="! ${HOST%%.*}> "
SHELL=/usr/bin/ksh
export CDPATH EDITOR ENV EXINIT FCEDIT HISTSIZE HOST MAIL PATH PS1
export SHELL
biff y
tset -I
stty erase \^? kill \^U intr \^C
umask 0022
alias mail=/usr/ucb/mailx
OSTYPE=`uname`
How it works?
CDPATH Directories searched by cd command.
EDITOR Sets default editor.
ENV Name of script that is executed at startup.
EXINIT Sets options for ex and vi editors.
FCEDIT Editor used by the fc command.
HISTSIZE Number of history commands available (must be set before ksh is started).
PATH Directories searched for any file (command) name. Most important shell variable.
PS1 Primary prompt string; default is $.
SHELL Name of shell environment.
export Pass the value of shell variables, giving global meaning to them.
tset Initializes terminals, setting the TERM variable.
biff y System notifies user of new mail.
stty erase Sets delete character for command line edits.
umask Sets (eliminates) file default access permissions.
alias Allows commands (and options) to be abbreviated.
140
Note: .kshrc file: Contains shell commands executed whenever a new Korn shell is instigated
e.g. a sample .kshrc file contains: set -o trackall i.e. Locate commands as they are
defined.
Numeric Variables
ksh variables are strings or integers, depending on how they are defined. var=100
makes var the string '100'. integer var=100 makes var the integer 100.
String variables that are all digits can be treated as numbers.
To manipulate numeric variables using C-style expressions, use either $(( expression
)) to return the value of expression, or (( expression )) to return only an exit status
(true or false).
% integer x=1
% (( y=x*10 ))
% (( x+=1 ))
% print $x $y
2 10
141
Within $(( expression )) and (( expression )) you can use parentheses for grouping,
the arithmetic operators +, -, *, /, %, <<, >>, &, |, ~, ^, and the relational operators <,
>, <=, >=, ==, !=, &&, and ||.
Within the ((...)) syntax, variables need not be preceded by a dollar sign, and special
characters need not be quoted or escaped.
Array Variables
An array variable provides a way to index a list of values and can be defined by the set
command: Syntax: set -A arrayname [list]
Items in an array can be accessed by position (first item is at index 0). Syntax: $
{variable[index]}
Note: $variable refers to ${variable[0]}.
Example:
set -A array
array *0+=”one”
array*1+=”two”
array*2+=”three”
three=3
array*three+=”four”
for i in 0 1 2 3 ; do
print ${array[i]}
done
echo $ {array[three]}
Alternatively we can declare the array as: set -A array one two three four
Note:
1. arrays are supported by ksh nor by bash
2. The number of defined elements in an array variable is given by ${#variable[*]}.
e.g. print ${#array[*]} for above array will display 4
3. set -A others ${array[*]} will create a new array others with the size and values of
array where as: set -A others $,array**+- “five” six seven will define the new array
142
others of 7 elements and initialize the last three elements with the three new
values. Also: others[7]=eight ; others[8]=nine
2) Stage a1 (apply)
Lab Activities:
3) Stage v (verify)
Home Activities:
Practice the shell scripting functions discussed in the lab.
4) Stage a2 (assess)
Activity assessment and Viva voce at the end of lab.
143
LAB # 012
Statement Purpose:
This lab will give you insight of shell programs using C++ programming structs such as
conditional statement and loops
Activity Outcomes:
The primary objective of this lab is to implement:
Conditional statements using If statement
Coase statements
Loops
144
1) Stage J (Journey)
Introduction
If Statements
The basic form for if statements in korn shell ksh is:
if condition
then
statements
[elif condition
then
statements]
[else
statements]
fi
The then/else/elif/fi keywords take the place of braces ({})---braces mean something special to
the shell!
Examples of condition are (assuming integer a b):
(( a == 10 ))
(( b < 20 ))
[[ $person = steve ]]
[[ $person != todd ]]
(( (a < 10) || (a > 100) ))
[[ ($person != steve ) && ($person != todd ) ]]
The elif or else parts can be omitted.
Example If Statement
if [[ $person = steve ]]
then
print $person is on the sixth floor.
elif [[ $person = todd ]]
then
print $person is on the fifth floor.
elif [[ $person = markus ]]
then
print $person is on the fifth floor.
else
print "Who are you talking about?"
fi
-a filename exists?
145
-d filename is directory?
Example:
if [[ ! -f output.file ]]; then
print "output.file does not exist."
fi
Example using return code:
opt="-f -d -L"
if print - $opt | grep -q -e -d
then print "Option '-d' in list."
fi
Command Substitution
$(command) is literally replaced by the output from command (the Bourne shell syntax for this
was graves: `command`).
$ set -A today $(date)
$ print ${today[*]}
Mon Oct 20 07:31:58 EDT 1997
$ print ${#today[*]}
6
$ print "${today[1]} ${today[2]}, ${today[5]}"
Oct 20, 1997
While Statements
Basic form:
while condition
do
statements
done
condition has the same syntax as for if statements.
You can use break or continue or return inside a loop with the same meaning as in C.
146
Example:
#!/usr/local/bin/ksh
# Report type of executable file anywhere in search path.
#
path=$PATH
dir=${path%%:*}
while [[ -n $path ]]; do
if [[ -x $dir/$1 && ! -d $dir/$1 ]]; then
file $dir/$1
return
fi
path=${path#*:}
dir=${path%%:*}
done
print "File not found."
return 1
Case Selection
The basic form of the case statement is:
case expression in
pattern1 )
statements ;;
pattern2 )
statements ;;
.
.
esac
The statements corresponding to the first pattern matching the expression are executed, after
which the case statement terminates.
The expression is usually some variable's value.
The patterns can be plain strings, or they can be Korn shell patterns using *, ?, !, [], etc. (like file-
matching patterns).
A pattern can consist of several patterns separated by | (logical or), and the pattern can also be
written as (pattern).
Sample Case
case $person in
steve)
print "He's on the sixth floor." ;;
todd | markus)
print "He's on the fifth floor." ;;
*)
print I do not know $person. ;;
esac
For Loops
A for loop can be used to iterate over all items in an array or list.
Basic form:
for var [in list]
do
statements
done
If in list is omitted in a script, the list is assumed to be $* --- all the arguments to the script.
Examples:
for name in Jack Jill John Jane Dick
do
print "Next person is $name."
147
done
integer count=0
for arg in $@
do
let count='count+1'
print "argument $count: $arg"
done
for i in *.for
do
mv $i ${i%.for}.f
print ${i%.for}.f
done
Command Line Arguments
Arguments given to a shell script on the command line when it is invoked are available through
the variable $* (a space separated list) and $@ (a list with each argument double quoted
separately). Individual arguments to the shell script are referenced as $1, $2, $3, etc., and $0 is
the name of the shell script itself.
$# indicates how many arguments were passed.
Example (print out all arguments to a shell script):
#!/usr/local/bin/ksh
integer i=1
for arg in $@
do
print "Argument $i is '$arg'."
(( i+=1 ))
done
return 0
At a time you can have 9 arguments to be stored in the variables $1 to $9. The shift
command moves parameters one position left i.e. $1=$2, $2=$3,…..,$9= 10 th command
line argument.
3) Stage v (verify)
Home Activities:
4) Write a shell script that reads 10 number from user and then prints all those numbers that
are odd
5) Find prime numbers from an array
4) Stage a2 (assess)
Activity assessment and Viva voce at the end of lab.
148
LAB # 13
Statement Purpose:
This lab will give you’ll use command line arguments with shell scripting.
Activity Outcomes:
The primary objective of this lab is to implement the shell scripting functions:
Using command line arguments
Using functions
149
1) Stage J (Journey)
Introduction
Arguments given to a shell script on the command line when it is invoked are available
through the variable $* (a space separated list) and $@ (a list with each argument double
quoted separately). Individual arguments to the shell script are referenced as $1, $2, $3, etc.,
and $0 is the name of the shell script itself.
$# indicates how many arguments were passed.
Functions
Functions are used to structure the script code.
Functions can be defined any where in the shell script, however, these must be defined
before invoking.
Syntax: fname() {
Statements }
When a function is invoked, the positional parameters to the script $*, $@, $#, $1…$9
are replaced by the parameters in the function. That is how the parameters are passed
to the function. When the function finishes, they are restored to their previous values.
We can make functions return numeric values using the return command
Local variables can be declared within shell functions by using the local keyword, the
variable is then only in scope within the function.
2) Stage a1 (apply)
Lab Activities:
Example:
print out all arguments to a shell script:
#!/usr/local/bin/ksh
integer i=1
for arg in $@
do
print "Argument $i is '$arg'."
(( i+=1 ))
done
return 0
At a time you can have 9 arguments to be stored in the variables $1 to $9. The shift
command moves parameters one position left i.e. $1=$2, $2=$3,…..,$9= 10th command
line argument.
Activity 1:
150
Using function:
myvar=global
f1()
, local myvar=”local”
echo f1 is called and the value of myvar is $myvar
echo $# arguments are passed to it and their values are $@
}
echo Script started
echo $# arguments are passed to the script which are: $*
f1 arg1 arg2 arg3
echo the value of global variable myvar is $myvar
echo after calling the function f1, the arguments in the script are $*
f2()
{ echo f2 is called, the value of myvar is $myvar
while true ; do
echo –n Are you ok(yes or no)?
read x
case “$x” in
y | yes) return 0;;
n | no) return 1;;
*) echo “Answer: yes or no”
esac
done
}
if [ f2 –eq 1]
echo thanks God
else
echo Get well soon
fi
exit 0
3) Stage v (verify)
Home Activities:
Write a shell script that reads 10 number from user and then prints all those numbers
that are odd
Find prime numbers from an array
4) Stage a2 (assess)
Activity assessment and Viva voce at the end of lab.
151
LAB # 14
Statement of Purpose:
This lab will introduce the basic concept of file arrays in shell scripting
Activity Outcomes:
This lab teaches you the following topics:
1. Creating arrays
2. Accessing arrays
3. Performing different operations such as deleting, sorting on arrays
152
1) Stage J (Journey)
What Are Arrays?
Arrays are variables that hold more than one value at a time. Arrays are organized like a table. Let’s
consider a spreadsheet as an example. A spreadsheet acts like a two-dimensional array. It has both
rows and columns, and an individual cell in the spreadsheet can be located according to its row and
column address. An array behaves the same way. An array has cells, which are called elements, and
each element contains data. An individual array element is accessed using an address called an index
or subscript.
Most programming languages support multidimensional arrays. A spreadsheet is an example of a
multidimensional array with two dimensions, width and height. Many languages support arrays with
an arbitrary number of dimensions, though two- and three-dimensional arrays are probably the
most commonly used.
Arrays in bash are limited to a single dimension. We can think of them as a spreadsheet with a single
column. Even with this limitation, there are many applications for them. Array support first appeared
in bash version 2. The original Unix shell program, sh, did not support arrays at all.
Creating an Array
Array variables are named just like other bash variables, and are created automatically when they
are accessed. Here is an example:
[
Using the -a option, this example of declare creates the array a.
where name is the name of the array and subscript is an integer (or arithmetic expression) greater
than or equal to zero. Note that the first element of an array is subscript zero, not one. value is a
string or integer assigned to the array element.
Multiple values may be assigned using the following syntax:
where name is the name of the array and value... are values assigned sequentially to elements of the
array, starting with element zero. For example, if we wanted to assign abbreviated days of the week
to the array days, we could do this:
153
It is also possible to assign values to a specific element by specifying a subscript for each
value:
The array elements can be accessed using array name and the index of the element to be accessed.
Index.
Array Operations
There are many common array operations. Such things as deleting arrays, determining
their size, sorting, etc. have many applications in scripting.
The subscripts * and @ can be used to access every element in an array. As with positional
parameters, the @ notation is the more useful of the two. Here is a demonstration:
154
Sorting an Array
Just as with spreadsheets, it is often necessary to sort the values in a column of data. The shell has
no direct way of doing this, but it's not hard to do with a little coding:
Deleting an Array
To delete an array, use the unset command:
2) Stage a1 (apply)
Activity 1
Write a shell script that
155
Solution:
#! /bin/bash
# To declare static Array
arr=(Ali ahemd 1 umar asad hassan)
# Size of an Array
echo ${#arr[@]} # 6
echo ${#arr[*]} # 6
# Search in Array
echo ${arr[@]/*[aA]*/} # 1
156
Activity 2
Write a shell script that
Solution:
# !/bin/bash
# To input array at run
# time by using while-loop
# Increment the i = i + 1
i=`expr $i + 1`
done
while [ $i -lt $n ]
do
echo ${a[$i]}
# To increment index
# by 1, i=i+1
i=`expr $i + 1`
done
4) Stage v (verify)
Home Activities:
5) Write a shell script that reads 10 number from user and then prints all those numbers
that are odd
157
4) Stage a2 (assess)
Activity assessment and Viva voce at the end of lab.
158