Shell Scripting
Shell Scripting
PDF
Written by Vivek Gite <vivek@nixcraft.com>
PDF generated using the open source mwlib toolkit. See http://code.pediapress.com/ for more information.
PDF generated at: Sun, 27 Sep 2009 19:47:41 CET
Contents
Articles
Linux Shell Scripting Tutorial -A Beginner's handbook:About 1
References
Article Sources and Contributors 209
Image Sources, Licenses and Contributors 212
Article Licenses
License 213
Linux Shell Scripting Tutorial - A Beginner's handbook:About 1
Audience
This book is for students and Linux System Administrators. It provides the skills to read, write, and debug Linux
shell scripts using bash shell. The book begins by describing Linux and simple scripts to automate frequently
executed commands and continues by describing conditional logic, user interaction, loops, menus, traps, and
functions. Finally, book covers various sys admin related scripts such as making a backup, using cron jobs, writing
interactive tools, web based tools, remote login, ftp and database backup related scripts. This book is intended for
Linux system administrators or students who have mastered the basics of a Linux Operating System. You should be
able to:
• Login to local or remote Linux system.
• Use basic Linux commands, such as cp, mv, rm, man,less, chmod and others.
• Create and edit text files in vi or any other text editor.
• GUI is not required except for interactive GTK+ based GUI scripts.
Licensing Information
This book is available under Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported [2].
• You are free:
• to Share — to copy, distribute and transmit the work
• to Remix — to adapt the work
• Under the following conditions:
• Attribution — If you republish this content, we require that you:
1. Indicate that the content is from "Linux Shell Scripting Tutorial - A Beginner's handbook" (http://bash.
cyberciti.biz/guide/Main_Page), and nixCraft (http://nixcraft.com/).
2. Hyperlink to the original article on the source site (e.g., http://bash.cyberciti.biz/guide/What_Is_Linux)
3. Show the author name (e.g., Vivek Gite) for all pages.
4. Hyperlink each contributors name back to their profile page on the source wiki (e.g., http://bash.cyberciti.biz/
guide/User:USERNAME)
• Noncommercial — You may not use this work for commercial purposes including the Internet ad supported
websites or any sort of print media.
• Share Alike — If you alter, transform, or build upon this work, you may distribute the resulting work only under
the same or similar license to this one.
With the understanding that:
• Waiver — Any of the above conditions can be waived if you get permission from the copyright holder (i.e. the
Author: Vivek Gite).
• Other Rights — In no way are any of the following rights affected by the license:
• Your fair dealing or fair use rights;
• The author's moral rights;
• Rights other persons may have either in the work itself or in how the work is used, such as publicity or privacy
rights.
Linux Shell Scripting Tutorial - A Beginner's handbook:About 2
• Notice — For any reuse or distribution, you must make clear to others the license terms of this work. The best
way to do this is with a link to this web page (http://bash.cyberciti.biz/guide/
Linux_Shell_Scripting_Tutorial_-_A_Beginner%27s_handbook:About).
History
• Ver.0.8 - 1998 - First draft with only 8 pages.
• Ver.0.9 - 2000 - Second draft with a few more pages.
• Ver.1.0 - 2002 - Third draft published on freeos.com.
• Ver.1.5r3 - 2004 - Updated version published on freeos.com.
• Ver.2.0.beta - Aug-2009 - Wiki started.
• This document is now in a wiki format.
• All user contributed content licensed under Attribution-Noncommercial-Share Alike 3.0 Unported.
Disclaimer
• This web site / wiki ("Site") provides educational learning information on Linux scripting for sys admin work, but
you are 100% responsible for what you do or don't do with it.
• The information compiled by Vivek Gite (and its contributors) as well as the links to complimentary material are
provided "as is" with no warranty, express or implied, for their accuracy or reliability.
• You use these sites at your own risk, and acknowledge that, while every effort has been made to correct errors
before they appear, this site may include certain inaccuracies, errors, or omissions. nixCraft makes no
representations as to the suitability, reliability, availability, timeliness, and accuracy of the information on this site
for any purpose.
• Using this site (cyberciti.biz) means you accept its terms [3].
• All trademark within are property of their respective holders.
• Although the author and its contributors believes the contents to be accurate at the time of publication, no liability
is assumed for them, their application or any consequences thereof. If any misrepresentations, errors or other need
of clarification is found, please contact the us immediately [4]. Please read our disclaimer [3] and privacy policy
[5]
.
Feedback
• Please give me your feedback. Whatever you see here, is based upon my own hard-earned experience. I have
taught myself both through trial and error. Shoot me an email at vivek@nixcraft.com [7].
References
[1] http:/ / vivekgite. com/
[2] http:/ / creativecommons. org/ licenses/ by-nc-sa/ 3. 0/
[3] http:/ / www. cyberciti. biz/ tips/ disclaimer
[4] http:/ / www. cyberciti. biz/ tips/ contact_us
[5] http:/ / www. cyberciti. biz/ tips/ privacy
[6] http:/ / www. cyberciti. biz/
[7] mailto:vivek@nixcraft. com
4
What Is Linux
← Main Page Home → Who created Linux →
Linux is a free open-source operating system based on Unix. Linus Torvalds originally created Linux with the
assistance of developers from around the world. Linux is:
• Free
• Unix Like
• Open Source
• Network operating system
Strictly speaking, Linux is a kernel. A kernel provides access to the computer hardware and control access to
resources such as:
• Files and data.
• Running programs.
• Loading programs into memory.
• Networks.
• Security and firewall.
• Other resources etc.
The kernel decides who will use a resource, for how long and when.You can download the Linux kernel from the
official web site. However, the Linux kernel itself is useless unless you get all the applications such as text editors,
email clients, browsers, office applications, etc. Therefore, someone came up with idea of a Linux distribution. A
typical Linux distribution includes:
• Linux kernel.
• GNU application utilities such as text editors, browsers etc.
• Collection of various GUI (X windows) applications and utilities.
• Office application software.
• Software development tools and compilers.
• Thousands of ready to use application software packages.
• Linux Installation programs/scripts.
• Linux post installation management tools daily work such as adding users, installing applications, etc.
• And, glued together by the shell.
Corporate and small businesses users need support while running Linux, so companies such as Red Hat or Novell
provide Linux tech-support and sell it as product. Nevertheless, community driven Linux distributions do exist such
as Debian, Gentoo and they are entirely free. There are over 200+ Linux distributions.
External links
• Linus's Blog [2]
References
[1] GNU/Linux (http:/ / www. gnu. org/ gnu/ gnu-linux-faq. html) FAQ by Richard
[2] http:/ / torvalds-family. blogspot. com/
Linux is available for download over the internet. However, this is only useful if your internet connection is fast.
Another way is to order the CD-ROMs, which saves time, and the installation is fast and automatic. I recommend the
following most popular Linux distributions.
If you are in India then you can get a Linux distribution from the leading computer magazines such as PC Quest or
Digit. Most Linux books from you local bookstore also include a Linux distribution. See the list of recommended
Linux books.
See the Linux installation section, which provides guidance and step-by-step instructions for installing Linux.
You can use Linux as a server operating system or as a stand alone operating system on your PC. As a server
operating system it provides different services/network resources to a client. A server operating system must be:
• Stable
• Robust
• Secure
• High performance
Linux offers all of the above characteristics plus it is free and open source. It is an excellent operating system for:
• Desktop computer
• Web server
• Software development workstation
• Network monitoring workstation
• Workgroup server
• Killer network services such as DHCP, Firewall, Router, FTP, SSH, Mail, Proxy, Proxy Cache server etc.
The kernel is heart of the Linux operating system. It manages the resources of Linux such as:
• File management
• Multitasking
• Memory management
• I/O management
• Process management
• Device management
• Networking support including IPv4 and IPv6
• Advanced features such as virtual memory, shared libraries, demand loading, shared copy-on-write executables
etc
The kernel decides who will use these resources and for how long and when. It runs your programs or sets up to
execute binary files. The kernel acts as an intermediary between the computer hardware and various applications.
What is Linux Kernel 8
Computers understand the language of zeros and ones known as binary language. In the early days of computing,
instructions were provided using binary language, which is difficult for all of us to read and write. Therefore, in an
operating system there is a special program called the shell. The shell accepts human readable commands and
translates them into something the kernel can read and process.
What Is a Shell?
• The shell is a user program or it is an environment provided for user interaction.
• It is a command language interpreter that executes commands read from the standard input device such as
keyboard or from a file.
• The shell started when you log in or open a console (terminal).
• Quick and dirty way to execute utilities.
• Thg shell is not part of system kernel, but uses the system kernel to execute programs, create files etc.
• Several shells are available for Linux including:
• BASH ( Bourne-Again SHell ) - Most common shell in Linux. It's Freeware shell.
• CSH (C SHell) - The C shell's syntax and usage are very similar to the C programming language.
• KSH (Korn SHell) - Created by [[David Korn] at AT & T Bell Labs.
• TCSH - It is an enhanced but completely compatible version of the Berkeley UNIX C shell (CSH).
Please note that each shell does the same job, but each understands different command syntax and provides different
built-in functions. Under MS-DOS, the shell name is COMMAND.COM which is also used for the same purpose,
What is Linux Shell 9
cat /etc/shells
echo $SHELL
ps $$
ps -p $$
References
[1] Command to find out current shell name (http:/ / www. cyberciti. biz/ tips/ how-do-i-find-out-what-shell-im-using. html) from the nixCraft
FAQ section.
Unix philosophy
→ ← What is Linux Home → But how do you use the shell
Shell →
The Unix philosophy is philosophical approaches to developing software based on the experience of leading
developers of the Unix operating system. The following philosophical approaches also applies to Linux operating
systems.
• Do one thing and do it well - Write programs that do one thing and do it well. Write programs to work together.
Write programs to handle text streams, because that is a universal interface.
• Everything is file - Ease of use and security is offered by treating hardware as a file.
• Small is beautiful
• Store data and configuration in flat text files - Text file is a universal interface. Easy to create, backup and move
files to another system.
• Use shell scripts to increase leverage and portability - Use shell script to automate common tasks across various
UNIX / Linux installations.
• Chain programs together to complete complex task - Use shell → pipes and → filters to chain small utilities that
perform one task at time.
• Choose portability over efficiency.
• Keep it Simple, Stupid (KISS).
Unix philosophy 10
External links
• Wikipedia:Unix philosophy
• The Unix Philosophy in One Lesson [1]
References
[1] http:/ / www. catb. org/ ~esr/ writings/ taoup/ html/ ch01s07. html
To use the shell you simply type commands. A command is a computer program, which is built to perform a specific
task. Examples of commands include:
ls
clear
cal
date
If your Linux system is booted into a text mode, you can start using the shell as soon as you log in. If you started in a
graphical mode (GUI), such as the Gnome desktop or Kde desktop, you can open a shell by going to Applications >>
System Tools >> Terminal. Alternatively, you can switch to a virtual console by pressing Ctrl-Alt-F1 and logging in
with your username and password.
Normally shells are interactive. It means the shell will accept command from you (via keyboard) and execute them.
However, if you store a sequence of commands to a text file and tell the shell to execute the text file instead of
entering the commands, that is known as a shell program or shell script.
Shell script defined as - "a series of command(s) stored in a plain text file". A shell script is similar to a batch file in
MS-DOS, but it is much more powerful as compare to MS-DOS shell.
Shell scripts are useful for automating process that you repeat at the prompt.
Advantages
• Easy to use.
• Quick start, and interactive debugging.
• Time Saving.
• Sys Admin task automation.
Disadvantages
• Compatibility problems between different platforms.
• Slow execution speed.
• A new process launched for almost every shell command executed.
Learning Objectives
After completing this tutorial, you will be able to:
• Understand the basis of Linux shell scripting.
• Write shell scripts and use it to save time with automated scripts.
• Customizing shell start-up files.
• Creating nifty utilities.
• Control your administration tasks such as Linux user management, Linux system monitoring etc.
Chapter 1 Challenges
→ ← Why shell scripting Home Chapter 2: Getting Started With Shell Programming →
Bash is the shell, or command language interpreter, for the Linux operating system. The name is an acronym for the
Bourne-Again SHell, a pun on Stephen Bourne, the author of the direct ancestor of the current Unix shell sh, which
appeared in the Seventh Edition Bell Labs Research version of Unix Bash Reference Manual[1] .
Introduction to BASH
• Developed by GNU project.
• The default Linux shell.
• Backword-compatible with the original sh UNIX shell.
• Bash is largely compatible with sh and incorporates useful features from the Korn shell ksh and the C shell csh.
• Bash is the default shell for Linux. However, it does runs on every version of Unix and a few other operating
systems such as ms-dos, os/2, and Windows platforms.
Quoting from the offcial Bash home page:
Bash is the shell, or command language interpreter, that will appear in the GNU operating system. It is intended to
conform to the IEEE POSIX P1003.2/ISO 9945.2 Shell and Tools standard. It offers functional improvements over sh
for both programming and interactive use. In addition, most sh scripts can be run by Bash without modification.
External links
• Bash home page [2]
References
[1] Bash Reference Manual.
[2] http:/ / www. gnu. org/ software/ bash/ bash. html
Shell commands
→ ← The bash shell Home → The role of shells in the Linux environment →
type command
The type command can be used to find out if command is builtin or external binary file.
type -a ls
Sample Output:
ls is /bin/ls
type -a history
Sample Output:
However, some commands are supplied as of both internal and external commands. For example:
type -a true
type -a echo
Shell commands 17
Sample Outputs:
• pwd
• read
• readonly
• return
• select
• set
• shift
• shopt
• source
• suspend
• test
• time
• times
• trap
• true
• type
• typeset
• ulimit
• umask
• unalias
• → unset
• until
• → variables
• while
The role of shells in the Linux environment 19
Shell is used for various purposes under Linux. Linux user environment is made of the following components:
• Kernel - The core of Linux operating system.
• Shell - Provides an interface between the user and the kernel.
• Terminal emulator - The xterm program is a terminal emulator for the X Window System. It allows user to enter
commands and display back their results on screen.
• Linux Desktop and Windows Manager - Linux desktop is collection of various software apps. It includes the file
manger, the windows manager, the Terminal emulator and much more. KDE and Gnome are two examples of the
complete desktop environment in Linux.
Login
User can login locally into the console when in runlevel # 3 or graphically when in runlevel # 5. In both cases you
need to provide username and password. Bash uses the following initialization and start-up files:
1. /etc/profile - The systemwide initialization file, executed for login shells.
2. /etc/bash.bashrc - The systemwide per-interactive-shell startup file.
3. /etc/bash.logout - The systemwide login shell cleanup file, executed when a login shell exits.
4. $HOME/.bash_profile - The personal initialization file, executed for login shells.
5. $HOME/.bashrc - The individual per-interactive-shell startup file.
6. $HOME/.bash_logout - The individual login shell cleanup file, executed when a login shell exits.
7. $HOME/.inputrc - Individual readline initialization file.
Login Shell
Login shells are first shell started when you log in to the system. Login shells set environment which is exported to
non-login shells. Login shell calls the following when a user logs in:
• /etc/profile runs first when a user logs in runlevel # 3.
• /etc/profile.d
• $HOME/.bash_profile, $HOME/.bash_login, and $HOME/.profile, runs second when a user logs in in that order.
$HOME/.bash_profile calls $HOME/.bashrc, which calls /etc/bashrc (/etc/bash.bashrc).
Non-Login Shell
• When an interactive shell that is not a login shell is started, bash reads and executes commands from
/etc/bash.bashrc or /etc/bashrc and $HOME/.bashrc, if these files exist. First, it calls $HOME/.bashrc. This calls
/etc/bash.bashrc, which calls /etc/profile.d.
In Linux, a lot of work is done using a command line shell. Linux comes preinstalled with Bash. Many other shells
are available under Linux:
• tcsh - An enhanced version of csh, the C shell.
• ksh - The real, AT&T version of the Korn shell.
• csh - Shell with C-like syntax, standard login shell on BSD systems.
• zsh - A powerful interactive shell.
• scsh- An open-source Unix shell embedded within Scheme programming language.
To find the list of available shell packages under Debian Linux / Ubuntu Linux, enter:
cat /etc/shells
Sample outputs:
/bin/sh
/bin/bash
/sbin/nologin
/bin/tcsh
/bin/csh
/bin/zsh
/bin/ksh
Other standard shells 21
which command
You can also use the which command to display the full path of (shell) commands:
which commandname
which bash
Sample outputs:
/bin/bash
For each of its command line arguments it prints to stdout (screen) the full path of the executables that would have
been executed when this argument had been entered at the shell prompt:
which date
which gcc
which vi
→ ← The role of shells in the Linux environment Home → Hello, World! Tutorial →
#!/bin/bash
echo "Hello, World!"
echo "Knowledge is power."
Save and close the file. You can run the script as follows:
./hello.sh
Sample outputs:
chmod +x hello.sh
./hello.sh
Sample Outputs:
Hello, World!
Knowledge is power.
See also
• chmod command
• vi command
Shebang
→ ← Hello, World! Tutorial Home → Shell Comments
→
The #! syntax used in scripts to indicate an interpreter for execution under UNIX / Linux operating systems. Most
Linux shell and perl / python script starts with the following line:
#!/bin/bash
OR
#!/usr/bin/perl
OR
#!/usr/bin/python
/bin/sh
For a system boot script, use /bin/sh:
#!/bin/sh
sh is the standard command interpreter for the system. The current version of sh is in the process of being changed to
conform with the POSIX 1003.2 and 1003.2a specifications for the shell.
#! /bin/sh
### BEGIN INIT INFO
# Provides: policykit
# Required-Start: $local_fs
# Required-Stop: $local_fs
# Default-Start: 2 3 4 5
# Default-Stop:
# Short-Description: Create PolicyKit runtime directories
# Description: Create directories which PolicyKit needs at
runtime,
# such as /var/run/PolicyKit
### END INIT INFO
case "$1" in
start)
mkdir -p /var/run/PolicyKit
chown root:polkituser /var/run/PolicyKit
chmod 770 /var/run/PolicyKit
;;
stop|restart|force-reload)
;;
*)
echo "Usage: $SCRIPTNAME {start|stop|restart|force-reload}" >&2
exit 3
;;
esac
External links
• Explain: #!/bin/bash [4] - or #!/bin/bash -- In A Shell Script
• Shebang (Unix)
References
[1] Howto Make Script More Portable With #!/usr/bin/env As a Shebang (http:/ / www. cyberciti. biz/ tips/
finding-bash-perl-python-portably-using-env. html) FAQ by nixCraft.
[2] Bash man page and the official documentation.
[3] extracts from 4.0BSD (http:/ / www. in-ulm. de/ ~mascheck/ various/ shebang/ sys1. c. html) /usr/src/sys/newsys/sys1.c.
[4] http:/ / www. cyberciti. biz/ faq/ binbash-interpreter-spoofing/
Shell Comments
→ ← Shebang Home → Setting up permissions on a script
→
#!/bin/bash
# A Simple Shell Script To Get Linux Network Information
# Vivek Gite - 30/Aug/2009
echo "Current date : $(date) @ $(hostname)"
echo "Network configuration"
/sbin/ifconfig
The first line is called a → shebang or a "bang" line. The following are the next two lines of the program:
• A word or line beginning with # causes that word and all remaining characters on that line to be ignored.
• These lines aren't statements for the bash to execute. In fact, the bash totally ignores them.
• These notes, called comments.
• It is nothing but explanatory text about script.
• It make source code easier to understand.
• These notes, are for humans and other sys admins.
• It help other sys admins to understand your code, logic and it helps them to modify a script you wrote.
External links
• Shell scripting: Put multiple line comment [1]
References
[1] http:/ / www. cyberciti. biz/ faq/ bash-comment-out-multiple-line-code/
Setting up permissions on a script 25
The chmod command (change mode) is a shell command in Linux. It can change file system modes of files and
directories. The modes include permissions and special modes. Each shell script must have the execute permission.
Mode can be either a symbolic representation of changes to make, or an octal number representing the bit pattern for
the new mode bits.
Examples
Allowing everyone to execute the script, enter:
chmod +x script.sh
OR
OR
OR
ls -l script.sh
Set the permissions for the user and the group to read and execute only (no write permission), enter:
Remove read and execute permission for the group and user, enter:
man chmod
Please note that script must have both executable and read permission.
External links
• How to use chmod and chown command [1]
• Chmod Numeric Permissions Notation UNIX / Linux Command [2]
References
[1] http:/ / www. cyberciti. biz/ faq/ how-to-use-chmod-and-chown-command/
[2] http:/ / www. cyberciti. biz/ faq/ unix-linux-bsd-chmod-numeric-permissions-notation-command/
Execute a script
→ ← Setting up permissions on a Home → Debug a script →
script
chmod +x script.sh
./script.sh
You can also run the script directly as follows without setting the script execute permission:
bash script.sh
./script.sh
In last example, you are using . (dot) command which read and execute commands from filename in the current
shell. If filename does not contain a slash, file names in PATH are used to find the directory containing filename.
The specialty of dot (.) command is you do not have to setup an executable permission on script.
Debug a script 27
Debug a script
→ ← Execute a script Home → Chapter 2 Challenges
→
You need to run a shell script with -x option from the command line itself:
bash -x script-name
OR
You can also modify → shebang line to run an entire script in debugging mode:
#!/bin/bash -x
echo "Hello ${LOGNAME}"
echo "Today is $(date)"
echo "Users currently on the machine, and their processes:"
w
#!/bin/bash
### Turn on debug mode ###
set -x
External links
• How to debug a Shell [1] Script under Linux or UNIX.
References
[1] http:/ / www. cyberciti. biz/ tips/ debugging-shell-script. html
Chapter 2 Challenges
→ ← Debug a script Home Chapter 3:The Shell Variables and Environment →
• Write the following shell script, and note down the it's output:
• Write a program that prints your favorite movie name. It should print director name on the next line.
• Write a shell script that prints out your name and waits for the user to press the [Enter] key before the script ends.
• List 10 builtin and external commands.
• Cd to /etc/init.d and view various system init scripts.
Variables in shell
← Chapter 3:The Shell Variables and Home → Assign values to shell variables
Environment →
You can use variables to store data and configuration options. There are two types of variable as follows:
System Variables
Created and maintained by Linux bash shell itself. This type of variable defined in CAPITAL LETTERS. You can
configure aspects of the shell by modifying system variables such as PS1, PATH, LANG,HISTSIZE,and DISPLAY
etc.
set
OR
env
OR
printenv
BASH=/bin/bash
BASH_ARGC=()
BASH_ARGV=()
BASH_LINENO=()
BASH_SOURCE=()
BASH_VERSINFO=([0]="3" [1]="2" [2]="39" [3]="1" [4]="release"
[5]="i486-pc-linux-gnu")
BASH_VERSION='3.2.39(1)-release'
COLORTERM=gnome-terminal
COLUMNS=158
DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-FSGj0JzI4V,guid=7f59a3dd0813f52d6296ee40
DESKTOP_SESSION=gnome
DIRSTACK=()
DISPLAY=:0.0
Variables in shell 30
EUID=1000
GDMSESSION=gnome
GDM_LANG=en_IN
GDM_XSERVER_LOCATION=local
GNOME_DESKTOP_SESSION_ID=this-is-deprecated
GPG_AGENT_INFO=/tmp/gpg-X7NqIv/S.gpg-agent:7340:1
GROUPS=()
GTK_RC_FILES=/etc/gtk/gtkrc:/home/vivek/.gtkrc-1.2-gnome2
HISTFILE=/home/vivek/.bash_history
HISTFILESIZE=500
HISTSIZE=500
HOME=/home/vivek
HOSTNAME=vivek-desktop
HOSTTYPE=i486
IFS=$' \t\n'
LANG=en_IN
LINES=57
LOGNAME=vivek
MACHTYPE=i486-pc-linux-gnu
MAILCHECK=60
OLDPWD=/home/vivek
OPTERR=1
OPTIND=1
ORBIT_SOCKETDIR=/tmp/orbit-vivek
OSTYPE=linux-gnu
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games
PIPESTATUS=([0]="0")
PPID=7542
PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '
PS2='> '
PS4='+ '
PWD=/tmp
SESSION_MANAGER=local/vivek-desktop:/tmp/.ICE-unix/7194
SHELL=/bin/bash
SHELLOPTS=braceexpand:emacs:hashall:histexpand:history:interactive-comments:monitor
SHLVL=1
SSH_AGENT_PID=7339
SSH_AUTH_SOCK=/tmp/ssh-IoFXYh7194/agent.7194
TERM=xterm
UID=1000
USER=vivek
USERNAME=vivek
WINDOWID=18874428
WINDOWPATH=7
XAUTHORITY=/home/vivek/.Xauthority
XDG_DATA_DIRS=/usr/local/share/:/usr/share/:/usr/share/gdm/
XDG_SESSION_COOKIE=186611583e30fed08439ca0047067c9d-1251633372.846960-528440704
Variables in shell 31
_=set
command_not_found_handle ()
{
if [ -x /usr/lib/command-not-found ]; then
/usr/bin/python /usr/lib/command-not-found -- $1;
return $?;
else
return 127;
fi
}
mp3 ()
{
local o=$IFS;
IFS=$(echo -en "\n\b");
/usr/bin/beep-media-player "$(cat $@)" & IFS=o
}
genpasswd ()
{
local l=$1;
[ "$l" == "" ] && l=16;
tr -dc A-Za-z0-9_ < /dev/urandom | head -c ${l} | xargs
}
xrpm ()
{
[ "$1" != "" ] && ( rpm2cpio "$1" | cpio -idmv )
}
HISTFILE The name of the file in which command history is saved. echo $HISTFILE
HISTFILE The name of the file in which command history is saved. echo $HISTFILE
HISTFILESIZE The maximum number of lines contained in the history file. echo $HISTFILESIZE
HISTSIZE The number of commands to remember in the command history. The default value is 500. echo $HISTSIZE
IFS The Internal Field Separator that is used for word splitting after expansion and to split lines into echo $IFS
words with the read builtin command. The default value is <space><tab><newline>.
LANG Used to determine the locale category for any category not specifically selected with a variable echo $LANG
starting with LC_.
Variables in shell 32
PATH The search path for commands. It is a colon-separated list of directories in which the shell looks for echo $PATH
commands.
TMOUT The default timeout for the read builtin command. Alsom in an interactive shell, the value is echo $TMOUT
interpreted as the number of seconds to wait for input after issuing the command. If not input
provided it will logout user.
echo $PATH
echo $PS1
All variable names must be prefixed with $ symbol. Try the following example to display the value of a variable
without using $ prefix:
echo HOME
echo $HOME
← Chapter 3:The Shell Variables and Home → Assign values to shell variables
Environment →
Assign values to shell variables 33
Creating and setting variables within a script is fairly simple. Use the following syntax:
varName=someValue
someValue is assigned to given varName and someValue must be on right side of = (equal) sign. If someValue is
not given, the variable is assigned the null string.
echo $varName
OR
echo ${varName}
For example, create a variable called vech, and give it a value 'Bus', type the following at a shell prompt:
vech=Bus
echo $vech
OR
echo ${vech}
However,
n=10 # this is ok
10=no# Error, NOT Ok, Value must be on right side of = sign.
Common Examples
Define your home directory:
myhome="/home/v/vivek"
echo $myhome
input="/home/sales/data.txt"
echo "Input file $input"
Store current date (you can store the output of date by running the shell command):
NOW=$(date)
echo $NOW
BACKUP="/nas05"
echo "Backing up files to $BACKUP/$USERNAME"
echo "MySHELL=>$SHELLCode<="
Sample outputs:
MySHELL=><=
The bash shell would try to look for an variable called SHELLCode instead of $SHELL. To avoid this kind of
ambiguity use ${varName} syntax i.e. ${BASH}Code:
echo "MySHELL=>${SHELL}Code<="
Sample outputs:
MySHELL=>/bin/bashCode<=
You can set the default shell variable value using the following syntax. For example, try to display the value of a
undefined variable called grandslam:
echo $grandslam
Nothing will be displayed as the variable grandslam was not set in the first place. If $grandslam unset, set name to
"Maria Sharapova", enter:
Sample outputs:
Maria Sharapova
→ ← Assign values to shell variables Home → Rules for Naming variable name →
Variable name must begin with alphanumeric character or underscore character (_), followed by one or more
alphanumeric character. Valid shell variable examples:
HOME
SYSTEM_VERSION
vech
no
Do not put spaces on either side of the equal sign when assigning value to variable. For example, the following is
valid variable declaration:
no=10
However, any of the following variable declaration will result into an error such as command not found:
no =10
no= 10
no = 10
no=10
No=11
NO=20
nO=2
All are different variable names, to display value 20 you've to use $NO variable:
You can define a NULL variable as follows (NULL variable is variable which has no value at the time of definition):
vech=
$ vech=""
echo $vech
Rules for Naming variable name 36
Do not use ?,* and other special characters, to name your variable.
?no=10 #invalid
out*put=/tmp/filename.txt #invalid
_GREP=/usr/bin/grep #valid
echo $_GREP
To display the value of a variable either use echo or printf command as follows:
echo $varName
OR
# Define variables
BACKUP="/nas05"
NOW=$(date +"%d-%m-%Y")
cd /etc
echo *.conf
Sample outputs:
\\ backslash
\a alert (BEL)
\b backspace
\f form feed
\n new line
\r carriage return
Display the value of shell variables 38
\t horizontal tab
\v vertical tab
\UHHHHHHHH
Unicode character with hex value HHHHHHHH (8 digits)
%% a single %
Where,
• w - Minimum field width.
• p - Display number of digits after the decimal point (precision).
• L - a conversion character. It can be:
• s - String
• d - Integer
• e - Exponential
• f - Floating point
vech="Car"
printf "%s\n" $vech
printf "%1s\n" $vech
printf "%1.1s\n" $vech
printf "%1.2s\n" $vech
printf "%1.3s\n" $vech
printf "%10.3s\n" $vech
printf "%10.1s\n" $vech
no=10
printf "%d\n" $no
big=5355765613
Display the value of shell variables 39
Quoting
→ ← Echo Command Home → Export Variables →
Your bash shell understand special characters with special meanings. For example, $var is used to display the
variable value. Bash expands variables and wildcards, for example:
echo $PATH
echo $PS1
echo /etc/*.conf
However, sometime you do not wish to use variables or wildcards. For example, do not print value of $PATH, but
just print $PATH on screen as a word. You can enable or disable the meaning of a special character by enclosing
them into a single or double quotes. This is also useful to suppress warnings and error messages while writing the
shell scripts.
OR
Quoting
There are three types of quotes
" Double The double quote ( "quote" ) protects everything enclosed between The double quotes allowes to print the value of $SHELL
Quotes two double quote marks except $, ', " and \.Use the double quotes variable, disables the meaning of wildcards, and finally
when you want only variables and command substitution. allows command substitution.
* Variable - Yes echo "$SHELL"
* Wildcards - No echo "/etc/*.conf"
* Command substitution - yes echo "Today is $(date)"
' Single The single quote ( 'quote' ) protects everything enclosed between The single quotes prevents displaying variable $SHELL
quotes two single quote marks. It is used to turn off the special meaning value, disabled the meaning of wildcards /etc/*.conf, and
of all characters. finally command substitution ($date) itself.
* Variable - No echo '$SHELL'
* Wildcards - No echo '/etc/*.conf'
* Command substitution - No echo 'Today is $(date)'
Quoting 40
` Back Use back quote ( `command-name` ) to execute command and The date command is executed and its output is
quote replace a command with its output within the same command-line. substituted back to echo command.
However, $(command-name) is encouraged syntax for substitution echo "Today is `date`"
as it is recommended by POSIX standard and it improves script echo "Today is $(date)"
readability. echo "$(ls /etc/*.conf)"
* Variable - Yes FILES=/etc/resolv.conf
* Wildcards - Yes echo "$(cat $FILE)"
* Command substitution - yes
Backslash
The backslash ( \ ) alters the special meaning of the ' and " i.e. it will escape or cancel the special meaning of the next
character. The following will display filename in double quote:
FILE="/etc/resolv.conf"
echo "File is \"$FILE\" "
Sample Outputs:
File is "/etc/resolv.conf"
The following will remove the special meaning of the dollar ( $ ) sign:
FILE="/etc/resolv.conf"
echo "File is \$FILE "
Sample Outputs:
File is $FILE
The export builtin automatically export to the environment of subshells. For example, Create the variable called
vech, and give it a value "Bus":
vech=Bus
echo $vech
bash
Now, display back the value of a variable vech with echo, enter:
echo $vech
You will get an empty line as the variable vech is not exported to subshell bash instance. To make the variable
known to subshells use export command. Try the following example at a console / terminal:
export backup="/nas10/mysql"
echo "Backup dir $backup"
bash
echo "Backup dir $backup"
By default all user defined variables are local. They are not exported to subshell. Use export command to export
variables and functions to subshell. If no variable names or function names are given, or if the -p option is given, a
list of all names that are exported in this shell is printed. An argument of -n says to remove the export property rom
subsequent NAMEs.
export -p
→← Home → Unset
Quoting →
Unset shell and environment variables 42
Use unset command to delete the variables during program execution. It can remove both functions and shell
variables.
vech=Bus
echo $vech
unset vech
echo $vech
You can accept input from the keyboard and assign an input value to a user defined shell variable using read
command.
Where,
• -p "Prompt" : Display prompt to user without a newline.
• variable1 : The first input (word) is assigned to the variable1.
• variable2 : The second input (word) is assigned to the variable2.
Handling Input
Create a script called greet.sh as follows:
#!/bin/bash
read -p "Enter your name : " name
echo "Hi, $name. Let us be friends!"
chmod +x greet.sh
./greet.sh
Sample Outputs:
Examples
Try the following examples.
#!/bin/bash
read -p "Enter the Internet domain name (e.g. nixcraft.com) : "
domain_name
whois $domain_name
Timeout Input
You can time out read command using the -t option. It causes read to time out and return failure if a complete line of
input is not read within TIMEOUT seconds. For example, if no input provided within 10 second, program will be
aborted (domain2.sh):
#!/bin/bash
read -t 10 -p "Enter the Internet domain name (e.g. nixcraft.com) : "
domain_name
whois $domain_name
Handling Passwords
The -s option causes input coming from a terminal to not be displayed on the screen. This is useful for password
handling (readpass.sh):
#!/bin/bash
read -s -p "Enter Password : " my_password
echo
echo "Your password - $my_password"
You can perform math operations on Bash shell → variables. The bash shell has built-in arithmetic option. You can
also use external command such as expr and bc calculator.
$((expression))
$(( n1+n2 ))
$(( n1/n2 ))
$(( n1-n2 ))
Examples
Add two numbers on fly using the echo command:
echo $(( 10 + 5 ))
Add two numbers using x and y variable. Create a shell program called add.sh using a text editor:
#!/bin/bash
x=5
y=10
ans=$(( x + y ))
echo "$x + $y = $ans"
chmod +x add.sh
./add.sh
Sample Outputs:
5 + 10 = 15
Create an interactive program using the → read command called add1.sh using a text editor:
#!/bin/bash
read -p "Enter two numbers : " x y
ans=$(( x + y ))
echo "$x + $y = $ans"
chmod +x add1.sh
./add1.sh
Perform arithmetic operations 45
Sample Outputs:
** Exponentiation x=2 8
y=3
echo $(( x ** y ))
Order of Precedence
Operators are evaluated in order of precedence. The levels are listed in order of decreasing precedence (quoting form
the bash man page).
id++ id--
variable post-increment and post-decrement
++id --id
variable pre-increment and pre-decrement
- + unary minus and plus
! ~ logical and bitwise negation
** exponentiation
* / % multiplication, division, remainder
+ - addition, subtraction
<< >> left and right bitwise shifts
<= >= < >
comparison
== != equality and inequality
& bitwise AND
^ bitwise exclusive OR
| bitwise OR
&& logical AND
|| logical OR
expr?expr:expr
conditional operator
= *= /= %= += -= <<= >>= &= ^= |=
assignment
Perform arithmetic operations 46
expr1 , expr2
comma
declare -i y=10
echo $y
#!/bin/bash
# set x,y and z to an integer data type
declare -i x=10
declare -i y=10
declare -i z=0
z=$(( x + y ))
echo "$x + $y = $z"
chmod +x intmath.sh
./intmath.sh
Sample outputs:
10 + 10 = 20
0 + 10 = 10
• When you try to set the variable x to character 'a', shell converted it to an integer attribute i.e. zero number.
• You can create the constants variables using the readonly command or declare command.
• The readonly buitin syntax is as follows:
readonly var
readonly varName=value
declare -r var
declare -r varName=value
Example
• Create a constant variable called DATA and make it's value is always the same throughout the shell script i.e. it
can't be changed:
readonly DATA=/home/sales/data/feb09.dat
echo $DATA
# Error ... readonly variable
DATA=/tmp/foo
unset DATA
Sample outputs:
Chapter 3 Challenges
→ ← Create the constants Home Chapter 4: Conditionals Execution (Decision Making) →
variable
1. Make a backup of existing variable called PS1 to OLDPS1. Set PS1 to '$'. Reset your prompt using OLDPS1
variable.
2. Customize your bash prompt by setting PS1 variable to 'I Love Scripting '.
3. Edit your $HOME/.bashrc file and set your new PS1 variable.
4. Create a list of legal and illegal bash variable names. Describe why each is either legal or illegal.
5. Write a command to display the environment.
6. Write a shell script that allows a user to enter his or her top three ice cream flavors. Your script should then print
out the name of all three flavors.
7. Write a shell script that allows a user to enter any Internet domain name (host name such as www.cyberciti.biz).
Your script should than print out the IP address of the Internet domain name.
8. Write a shell script that allows a user to enter any existing file name. The program should then copy file to /tmp
directory.
9. Write a shell script that allows a user to enter directory name. The program should then create directory name in
/tmp directory.
10. Write a shell script that allows a user to enter three file names. The program should then copy all files to USB
pen.
11. Write a simple shell script where the user enters a pizza parlor bill total. Your script should then display a 10
percent tip.
12. Write a simple calculator program that allows user to enter two numeric values and operand as follows. The
program should then print out the sum of two numbers. Make sure it works according to entered operand.
You can use the if command to test a condition. For example, shell script may need to execute tar command only if a
certain condition exists (such as bakcup only on Friday night).
If today is Friday
execute tar command
otherwise
print an error message on screen.
#!/bin/bash
echo "Today is $(date)"
echo "Current directory : $(pwd)"
echo "What User Are Doing:"
w
echo $(( 5 + 2 ))
Sample Output:
7
Bash structured language constructs 50
Addition is 7. But,
Sample Output:
Answer is zero (0). Shell simple compared two number and returned result as true or false. Is 5 is less than 2? No. So
0 is returned. The Boolean (logical data) type is a primitive data type having one of two values
• True
• False
In shell:
• 0 value indicates false.
• 1 or non-zero value indicate true.
Examples
Now, it make no sense to use comparisons like above echo command. But, when you compare it with some value it
becomes very useful. For example:
Test command
→ ← Bash structured language constructs Home → if structures to execute code based on a condition →
The test command is used to check file types and compare values. Test is used in conditional execution. It is used
for:
• File attributes comparisons
• Perform string comparisons.
• Arithmetic comparisons.
OR
OR
OR
Sample Output:
Yes
You need to use the test command while make decision. Try the following examples and note down its output:
→ ← Bash structured language constructs Home → if structures to execute code based on a condition →
If structures to execute code based on a condition 52
Now, you can use the if statement to test a condition. if command The general syntax is as follows:
if condition
then
command1
command2
...
commandN
fi
OR
OR
if test -f /file/exists
then
command1
command2
...
commandN
fi
If given condition is true than the command1, command2..commandN are executed. Otherwise script continues
directly to the next statement following the if structure. Open a text editor and create the script called verify.sh:
#!/bin/bash
read -p "Enter a password" pass
if test "$pass" == "jerry"
then
echo "Password verified."
fi
chmod +x verify.sh
./verify.sh
Sample Outputs:
If structures to execute code based on a condition 53
Run it again:
./verify.sh
Sample Output:
The if structure is pretty straightforward. The read command will read the password and store it to variable called
pass. If $pass (i.e. password) is equal to "jerry", then "Password verified." is displayed. However, if it is not equal to
"jerry", the script does not print any message and script will go to the next statement. Here is another example
(number.sh):
#!/bin/bash
read -p "Enter # 5 : " number
if test $number == 5
then
echo "Thanks for entering # 5"
fi
if test $number != 5
then
echo "I told you to enter # 5. Please try again."
fi
Enter # 5 : 5 Thanks for entering # 5 Save and close the file. Run it as follows:
chmod +x number.sh
./number.sh
Sample Outputs:
Enter # 5 : 5
Thanks for entering # 5
Try it again:
./number.sh
Sample Outputs:
Enter # 5 : 11
I told you to enter # 5. Please try again.
If..else..fi
→ ← if structures to execute code based on a Home → Nested ifs →
condition
if..else..fi allows to make choice based on a condition. For example, find out if file exists (true condition) or not
(false condition) and take action based on a condition result.
if..then..else Syntax
if condition
then
condition is true
execute all commands up to else statement
else
if condition is not true then
execute all commands up to fi
fi
OR
else
if condition is not true then
execute all commands up to fi
fi
if/then/else Example
Update verify.sh as follows
##!/bin/bash
read -p "Enter a password" pass
if test "$pass" == "jerry"
then
echo "Password verified."
else
echo "Access denied."
fi
./verify.sh
If..else..fi 55
You have updated verify.sh and added an else statement to existing if command to create if..else..fi structure. If
$pass (i.e. password) is equal to "jerry", then "Password verified." is displayed. However, with else statement, the
script can display "Access denied." message on screen. This ensures that your script will always execute one of the
code block as follows:
if condition is true
then
print "Password verified message."
else # if condition is false
print "Access denied message."
fi
#!/bin/bash
read -p "Enter number : " n
if test $n -ge 0
then
echo "$n is positive number."
else
echo "$n number is negative number."
fi
chmod +x testnum.sh
./testnum.sh
#!/bin/bash
# Purpose: Detecting Hardware Errors
# Author: Vivek Gite <vivek@nixcraft.com>
# Note : The script must run as a cron-job.
# Last updated on : 28-Aug-2007
# -----------------------------------------------
Nested ifs
→ ← If..else..fi Home → Multilevel if-then-else →
You can put if command within if command and create the nested ifs as follows:
if condition
then
if condition
then
.....
..
do this
else
....
..
do this
fi
else
...
.....
do this
fi
Multilevel if-then-else
→ ← Nested ifs Home → The exit status of a command →
if..elif..else..fi allows the script to have various possibilities and conditions. This is handy, when you want to
compare one variable to a different values.
if condition
then
condition is true
execute all commands up to elif statement
elif condition1
then
condition1 is true
execute all commands up to elif statement
elif condition2
then
condition2 is true
execute all commands up to elif statement
elif conditionN
then
conditionN is true
execute all commands up to else statement
else
None of the above conditions are true
execute all commands up to fi
fi
In if..elif..else..fi structure, the block of the first true condition is executed. If no condition is true, the else block, is
executed.
Example
A simple shell script to determine if the given number is a negative or a positive number (numest.sh):
#!/bin/bash
read -p "Enter a number : " n
if [ $n -gt 0 ]; then
echo "$n is a positive."
elif [ $n -lt 0 ]
then
echo "$n is a negative."
elif [ $n -eq 0 ]
then
echo "$n is zero number."
else
Multilevel if-then-else 59
chmod +x numest.sh
./numest.sh
Each Linux command returns a status when it terminates normally or abnormally. You can use command exit status
in the shell script to display an error message or take some sort of action. For example, if tar command is
unsuccessful, it returns a code which tells the shell script to send an e-mail to sys admin.
Exit Status
• Every Linux command executed by the shell script or user, has an exit status.
• The exit status is an integer number.
• The Linux man pages stats the exit statuses of each command.
• 0 exit status means the command was successful without any errors.
• A non-zero (1-255 values) exit status means command was failure.
• You can use special shell variable called ? to get previously executed command. To print ? variable use the echo
command (
echo $?
date
echo $?
Sample Output:
date1
echo $?
ls /eeteec
The exit status of a command 60
echo $?
Sample Output:
According to ls man page - exit status is 0 if OK, 1 if minor problems, 2 if serious trouble.
ls -l /tmp
status=$?
echo "ls command exit stats - $status"
#!/bin/bash
# set var
PASSWD_FILE=/etc/passwd
chmod +x finduser.sh
./finduser.sh
Sample Outputs:
Run it again:
The exit status of a command 61
chmod +x finduser.sh
./finduser.sh
Sample Outputs:
You can combine the grep and if command in a single statement as follows:
Notice that standard output from grep command is ignored by sending them to /dev/null.
Conditional execution
→ ← The exit status of a command Home → Logical AND →
You can link two commands under bash shell using conditional execution based on the exit status of the last
command. This is useful to control the sequence of command execution. Also, yoy can do conditional execution
using the if statement. The bash support the following two conditional executions:
1. → Logical AND && - Run second command only if first is successful.
2. → Logical OR || - Run second command only if first is not successful.
Logical and (&&) is boolean operator. It can execute commands or shell functions based on the → exit status of
another command.
Syntax
command1 && command2
OR
command2 is executed if, and only if, command1 returns an → exit status of zero (true). In other words, run
command1 successfully and then run command2.
Example
Type the following at a shell prompt:
The → echo command will only run if the rm command exits successfully with a status of zero. If file is deleted
successfully the rm command set the exit stats to zero and echo command get executed.
External links
• How to display error message instantly when command fails [1]
References
[1] http:/ / www. cyberciti. biz/ tips/ shell-displaying-error-messages. html
Logical OR || 63
Logical OR ||
→ ← Logical AND Home → Logical Not !
→
Logical OR (||) is boolean operator. It can execute commands or shell functions based on the → exit status of another
command.
Syntax
command1 || command2
OR
First_command || Second_command
command2 is executed if, and only if, command1 returns a non-zero exit status. In other words, run command1
successfully or run command2.
Example
cat /etc/shadow 2>/dev/null || echo "Failed to open file"
The cat command will try to display /etc/shadow file and it (the cat command) sets the exit stats to non-zero value if
it failed to open /etc/shadow file. Therefore, 'Failed to open file' will be displayed cat command failed to open the
file.
test $(id -u) -eq 0 && echo "You are root" || echo "You are NOT root"
OR
test $(id -u) -eq 0 && echo "Root user can run this script." || echo
"Use sudo or su to become a root user."
Logical OR || 64
External links
• How to display error message instantly when command fails [1]
Logical Not !
→ ← Logical OR Home → Conditional expression →
Logical not (!) is boolean operator, which is used to test whether expression is true or not. For example, if file not
exits display an error on screen.
Syntax
! expression
Example
Try the following example:
OR
The → test command is used to check file types and compare values. You can also use [ as test command. It is used
for:
• File attributes comparisons
• Perform string comparisons.
• Arithmetic comparisons.
Syntax
[ condition ]
OR
[ ! condition ]
OR
OR
[ condition ] || false-command
OR
Examples
[ 5 == 5 ] && echo "Yes" || echo "No"
[ 5 == 15 ] && echo "Yes" || echo "No"
[ 5 != 10 ] && echo "Yes" || echo "No"
[ -f /etc/resolv.conf ] && echo "File /etc/resolv.conf found." || echo
"File /etc/resolv.conf not found."
[ -f /etc/resolv1.conf ] && echo "File /etc/resolv.conf found." || echo
"File /etc/resolv.conf not found."
Numeric comparison
→ ← Conditional expression Home → String comparison
→
The → test command can perform various numeric comparison using the following operators:
String comparison
→ ← Numeric Home → File attributes comparisons →
comparison
STRING1 = STRING2
Example
#!/bin/bash
read -s -p "Enter your password " pass
echo
if test "$pass" = "tom"
then
echo "You are allowed to login!"
fi
STRING1 != STRING2
Example
#!/bin/bash
read -s -p "Enter your password " pass
echo
if test "$pass" != "tom"
then
echo "Wrong password!"
fi
-z STRING
Example
#!/bin/bash
read -s -p "Enter your password " pass
echo
String comparison 68
if test -z $pass
then
echo "No password was entered!!! Cannot verify an empty
password!!!"
exit 1
fi
if test "$pass" != "tom"
then
echo "Wrong password!"
fi
Use the following file comparisons to test various file attributes. You can use the → test command or → conditional
expression using [.
-a file
True if file exists.
Example
[ -a /etc/resolv.conf ] && echo "File found" || echo "Not found"
-b file
True if file exists and is a block special file.
Example
[ -b /dev/zero ] && echo "block special file found" || echo "block
special file not found"
OR
-c file
True if file exists and is a character special file.
Example
[ -c /dev/tty0 ] && echo "Character special file found." || echo
"Character special file not found."
-d dir
True if file exists and is a directory.
Example
#!/bin/bash
DEST=/backup
SRC=/home
-e file
True if file exists.
Example
[ -e /tmp/test.txt ] && echo "File found" || echo "File not found"
-f file
True if file exists and is a regular file.
Example
[ ! -f /path/to/file ] && echo "File not found!"
A sample shell script that compare various file attributes and create webalizer (application that generates web pages
of analysis, from access and usage log) stats configuration file to given Internet domain name.
File attributes comparisons 70
#!/bin/bash
# Purpose: A Shell Script To Create Webalizer Stats Configration File
# Written by: Vivek Gite
# ---------------------------------------------------------------------
# Set vars
# Path to GeoIP DB
GEOIPDBPATH="/usr/local/share/GeoIP/GeoIP.dat"
# Make sure we got the Input else die with an error on screen
[ -z $DOMAIN ] && { echo "Please enter a domain name. Try again!"; exit
1; }
>$OUT
echo "LogFile $LOGFILE" >> $OUT
echo "LogType clf" >> $OUT
echo "OutputDir $CONFROOT/out" >> $OUT
echo "HistoryName $CONFROOT/webalizer.hist" >> $OUT
echo "Incremental yes" >> $OUT
echo "IncrementalName $CONFROOT/webalizer.current" >> $OUT
echo "HostName $DOMAIN" >> $OUT
echo "Quiet yes" >> $OUT
echo "FoldSeqErr yes" >> $OUT
echo "AllSearchStr yes" >> $OUT
echo "HideSite $DOMAIN" >> $OUT
File attributes comparisons 71
-g file
True if file exists and is set-group-id.
-h file
True if file exists and is a symbolic link.
-k file
True if file exists and its ‘‘sticky’’ bit is set.
-p file
True if file exists and is a named pipe (FIFO).
-r file
True if file exists and is readable.
-s file
True if file exists and has a size greater than zero.
-t fd
True if file descriptor fd is open and refers to a terminal. -u file== True if file exists and its set-user-id bit is set.
-w file
True if file exists and is writable.
-x file
True if file exists and is executable.
-O file
True if file exists and is owned by the effective user id.
File attributes comparisons 73
-G file
True if file exists and is owned by the effective group id.
-L file
True if file exists and is a symbolic link.
-S file
True if file exists and is a socket.
-N file
True if file exists and has been modified since it was last read.
Most Linux command can take different actions depending on the command line arguments supplied to the
command.
ls grate_stories_of
Sample Outputs:
ls is the name of an actual command and shell executed this command when you type command at shell prompt. The
first word on the command line is:
• ls - name of the command to be executed.
• Everything else on command line is taken as arguments to this command.
Consider the following example:
Examples
Try the following command and note down its command line arguments:
ls ls 0 N/A
ls /etc/resolv.conf ls 1 /etc/resolv.conf
All command line parameters ( positional parameters ) are available via special shell variable $1, $2, $3,...,$9.
#!/bin/bash
echo "The script name : $0"
echo "The value of the first argument to the script : $1"
echo "The value of the second argument to the script : $2"
echo "The value of the third argument to the script : $3"
echo "The number of arguments passed to the script : $#"
echo "The value of all command-line arguments : $*"
chmod +x cmdargs.sh
./cmdargs.sh bmw ford toyota
Sample outputs:
ls /tmp
./math 10 + 2
~/scripts/addzone cyberciti.com
~/scripts/adddomain cyberciti.biz '74.86.48.99' '2607:f0d0:1002:11::4'
/etc/init.d/named reload
/usr/rc.d/jail restart cyberciti.biz
How to use positional parameters 76
Shell script name ($0) Total number of arguments Actual Command line argument ($1,..,$9)
($#)
ls 1 /tmp
~/scripts/addzone 1 cyberciti.com
Bash shell set several special parameters. For example $? (see return values section) holds the return value of the
executed command.
• All command line parameters or arguments can be accessed via $1, $2, $3,..., $9.
• $* holds all command line parameters or arguments.
• $# holds the number of positional parameters.
• $- holds flags supplied to the shell.
• $? holds the return value set by the previously executed command.
• $$ holds the process number of the shell (current shell).
• $! hold the process number of the last background command.
Use echo command to display special shell parameters:
echo $#
status=$?
[ $status -eq 0 ] && echo "Lighttpd ... [Ok]" || echo "Lighttpd ...
[Failed]"
You can use the if command to check command line arguments. Many Linux commands display an error or usage
information when required command line option is not passed. For example, try the following command:
gcc
Sample outputs:
Try rm command:
rm
Sample outputs:
#!/bin/bash
# A shell script to lookup usernames in /etc/passwd file
# Written by: Vivek Gite
# Last updated on: Sep/10/2003
# -------------------------------------------------------
# Set vars
user=$1 # first command line argument
passwddb=/etc/passwd
chmod +x userlookup.sh
./userlookup.sh
Sample outputs:
./userlookup.sh kate
Sample outputs:
./userlookup.sh vivek
Sample outputs:
vivek found
Exit command
→ ← Create usage messages Home → The case statement →
exit N
• The exit statement is used to exit from the shell script with a status of N.
• Use the exit statement to indicate successful or unsuccessful shell script termination.
• The value of N can be used by other commands or shell scripts to take their own action.
• If N is omitted, the exit status is that of the last command executed.
• Use the exit statement to terminate shell script upon an error.
• If N is set to 0 means normal shell exit. Create a shell script called exitcmd.sh:
#!/bin/bash
echo "This is a test."
# Terminate our shell script with success message
exit 0
chmod +x exitcmd.sh
./exitcmd.sh
Sample outputs:
This is a test.
To see exit status of the script, enter (see → the exit status of a command for more information about special shell
variable $?) :
echo $?
#!/bin/bash
BAK=/data2
TAPE=/dev/st0
echo "Trying to backup ${BAK} directory to tape device ${TAPE} .."
# Okay back it up
tar cvf $TAPE $BAK 2> /tmp/error.log
if [ $? -ne 0 ]
then
# die with unsuccessful shell script termination exit status # 3
echo "An error occurred while making a tape backup, see
/tmp/error.log file".
exit 3
fi
# Terminate our shell script with success message i.e. backup done!
exit 0
chmod +x datatapebackup.sh
./datatapebackup.sh
echo $?
The case statement is good alternative to → multilevel if-then-else-fi statement. It enable you to match several values
against one variable. It is easier to read and write.
Syntax
The syntax is as follows:
case $variable-name in
pattern1)
command1
...
....
commandN
;;
pattern2)
command1
...
....
commandN
;;
patternN)
command1
...
....
commandN
;;
*)
esac
OR
case $variable-name in
pattern1|pattern2|pattern3)
command1
...
....
commandN
;;
pattern4|pattern5|pattern6)
command1
...
....
commandN
;;
The case statement 82
pattern7|pattern8|patternN)
command1
...
....
commandN
;;
*)
esac
• The case statement allows you to easily check pattern (conditions) and then process a command-line if that
condition evaluates to true.
• In other words the $variable-name is compared against the patterns until a match is found.
• *) acts as default and it is executed if no match is found.
• The pattern can also act as wildcards.
• You must include ;; at the end of each commandN. The shell executes all the statements up to the two semicolons
that are next to each other.
• The esac is always required to indicate end of case statement.
Example
Create a shell script called rental.sh:
#!/bin/bash
chmod +x rental.sh
./rental.sh
The case statement 83
./rental.sh jeep
./rental.sh enfield
./rental.sh bike
Sample outputs:
Sorry, I can not gat a *** Unknown vehicle *** rental for you!
For jeep rental is Rs.5 per k/m.
For enfield rental Rs.3 per k/m.
Sorry, I can not gat a bike rental for you!
The case statement first checks $rental against each option for a match. If it matches "car", the echo command will
display rental for car. If it matches "van", the echo command will display rental for van and so on. If it matches
nothing i.e. * (default option), an appropriate warning message is printed.
The following shell script demonstrate the concept of command line parameters processing using the case statement
(casecmdargs.sh):
#!/bin/bash
OPT=$1 # option
FILE=$2 # filename
-d|-D)
echo "Today is $(date)"
;;
*)
echo "Bad argument!"
echo "Usage: $0 -ecd filename"
echo " -e file : Edit file."
echo " -c file : Display file."
echo " -d : Display current date and time."
;;
esac
Run it as follows:
chmod +x casecmdargs.sh
./casecmdargs.sh
./casecmdargs.sh -e /tmp/file
./casecmdargs.sh -E /tmp/file
./casecmdargs.sh -e
./casecmdargs.sh -D
#!/bin/bash
# A shell script to backup mysql, webserver and files to tape
opt=$1
case $opt in
sql)
echo "Running mysql backup using mysqldump tool..."
;;
sync)
echo "Running backup using rsync tool..."
;;
tar)
echo "Running tape backup using tar tool..."
;;
*)
echo "Backup shell script utility"
echo "Usage: $0 {sql|sync|tar}"
echo " sql : Run mySQL backup utility."
echo " sync : Run web server backup utility."
echo " tar : Run tape backup utility." ;;
esac
chmod +x allinonebackup.sh
# run sql backup
The case statement 85
./allinonebackup.sh sql
# Dump file system using tape device
./allinonebackup.sh tar
# however, the following will fail as patterns are case sensitive
# you must use command line argument tar and not TAR, Tar, TaR etc.
./allinonebackup.sh TAR
Words can differ in meaning based on differing use of uppercase and lowercase letters. Linux allow a file to have
more than one name. For example, Sample.txt, SAMPLE.txt, and SAMPLE.TXT all are three different file names.
The case sensitive problem also applies to → the case statement. For example, our backup script can be executed as
follows:
./allinonebackup.sh tar
However, the following example will not work, as patterns are case sensitive. You must use command line argument
tar and not TAR, Tar, TaR etc:
./allinonebackup.sh TAR
However, you can get around this problem using any one of the following solution.
#!/bin/bash
# A shell script to backup mysql, webserver and files to tape
# allinonebackup.sh version 2.0
# -------------------------------------------------------
# covert all passed arguments to lowercase using
# tr command and here strings
opt=$( tr '[:upper:]' '[:lower:]' <<<"$1" )
case $opt in
sql)
Dealing with case sensitive pattern 86
Run it as follows:
./allinonebackup.sh TAR
./allinonebackup.sh TaR
[Tt][Aa][Rr]
#!/bin/bash
# A shell script to backup mysql, webserver and files to tape
opt=$1
#########################################################
# Use regex to match all command line arguments #
# [Tt][Aa][Rr] matches "tar", "TAR", "taR", "TaR", etc #
# [Ss][Qq][Ll] matches "sql", "SQL", "SQl", "SqL", etc #
#########################################################
case $opt in
[Ss][Qq][Ll])
echo "Running mysql backup using mysqldump tool..."
Dealing with case sensitive pattern 87
;;
[Ss][Yy][Nn][Cc])
echo "Running backup using rsync tool..."
;;
[Tt][Aa][Rr])
echo "Running tape backup using tar tool..."
;;
*)
echo "Backup shell script utility"
echo "Usage: $0 {sql|sync|tar}"
echo " sql : Run mySQL backup utility."
echo " sync : Run web server backup utility."
echo " tar : Run tape backup utilty." ;;
esac
Chapter 4 Challenges
→ ← Dealing with case sensitive pattern Home Chapter 5: Bash Loops
→
Bash shell can repeat particular instruction again and again, until particular condition satisfies. A group of instruction
that is executed repeatedly is called a loop. Bash supports:
• The for loop
• The → while loop
Each and every loop must:
• First, the variable used in loop condition must be initialized, then execution of the loop begins.
• A test (condition) is made at the beginning of each iteration.
• The body of loop ends with a statement that modifies the value of the test (condition) variable.
• Repeatedly execute a block of statements.
....
...
commandN
done
The for loop execute a command line once for every new value assigned to a var (variable) in specified list
(item1...itemN) i.e. repeat all statement between do and done till condition is not satisfied. The lists or values are
normally:
1. Strings
2. Numbers
3. Command line arguments
4. File names
5. Linux command output
Example
Create a shell script called testforloop.sh:
#!/bin/bash
for i in 1 2 3 4 5
do
echo "Welcome $i times."
done
chmod +x testforloop.sh
./testforloop.sh
The for loop statement 90
The for loop first creates i variable and assigned a number to i from the list of number from 1 to 5. The shell execute
echo statement for each assignment of i. This is known as iteration. This process will continue until all the items in
the list were not finished. See bash for loop examples [1] page for more information.
#!/bin/bash
# A simple shell script to print list of cars
for car in bmw ford toyota nissan
do
echo "Value of car is: $car"
done
#!/bin/bash
# A simple shell script to run commands
for command in date pwd df
do
echo
echo "*** The output of $command command >"
#run command
$command
echo
done
chmod +x forcmds.sh
./forcmds.sh
Sample outputs:
#!/bin/bash
# A shell script to verify user password database
files="/etc/passwd /etc/group /etc/shadow /etc/gshdow"
for f in $files
do
[ -f $f ] && echo "$f file found" || echo "*** Error - $f file
missing."
done
#!/bin/bash
# A simple shell script to display a file on screen passed as command
line argument
[ $# -eq 0 ] && { echo "Usage: $0 file1 file2 fileN"; exit 1; }
chmod +x forcmdargs.sh
./forcmdargs.sh /etc/resolv.conf /etc/hostname
Sample outputs:
------------------------------------------------
$(command-name)
`command-name`
var=$(command-name)
NOW=$(date)
echo $NOW
#!/bin/bash
echo "Printing file names in /tmp directory:"
for f in $(ls /tmp/*)
do
echo $f
done
#!/bin/bash
n=$1
# make sure command line arguments are passed to the script
if [ $# -eq 0 ]
then
echo "A shell script to print multiplication table."
echo "Usage : $0 number"
exit 1
fi
chmod +x multiplication.sh
./multiplication.sh
./multiplication.sh 13
Sample outputs:
The for loop statement 93
13 * 1 = 13
13 * 2 = 26
13 * 3 = 39
13 * 4 = 52
13 * 5 = 65
13 * 6 = 78
13 * 7 = 91
13 * 8 = 104
13 * 9 = 117
13 * 10 = 130
Further readings
• BASH For Loop Examples [1]
• KSH For Loop Examples [2]
References
[1] http:/ / www. cyberciti. biz/ faq/ bash-for-loop/
[2] http:/ / www. cyberciti. biz/ faq/ ksh-for-loop/
Nested for loops means loop within loop. They are useful for when you want to repeat something serveral times for
several things. For example, create a shell script called nestedfor.sh:
#!/bin/bash
# A shell script to print each number five times.
for (( i = 1; i <= 5; i++ )) ### Outer for loop ###
do
chmod +x nestedfor.sh
./nestedfor.sh
Nested for loop statement 94
Sample outputs:
1 1 1 1 1
2 2 2 2 2
3 3 3 3 3
4 4 4 4 4
5 5 5 5 5
For each value of i the inner loop is cycled through 5 times, with the variable j taking values from 1 to 5. The inner
for loop terminates when the value of j exceeds 5, and the outer loop terminates when the value of i exceeds 5.
Chessboard Example
A chessboard is the type of checkerboard used in the game of chess, and consists of 64 squares - eight rows and eight
columns arranged in two alternating colors. The colors are called "black" and "white". Let us write a shell script
called chessboard.sh to display a chessboard on screen:
#!/bin/bash
for (( i = 1; i <= 8; i++ )) ### Outer for loop ###
do
for (( j = 1 ; j <= 8; j++ )) ### Inner for loop ###
do
total=$(( $i + $j)) # total
tmp=$(( $total % 2)) # modulus
# Find out odd and even number and change the color
# alternating colors using odd and even number logic
if [ $tmp -eq 0 ];
then
echo -e -n "\033[47m "
else
echo -e -n "\033[40m "
fi
done
echo "" #### print the new line ###
done
chmod +x chessboard.sh
./chessboard.sh
Sample outputs:
Nested for loop statement 95
while [ condition ]
do
command1
command2
..
....
commandN
done
Command1..commandN will executes while a condition is true. To read a text file line-by-line, use the following
syntax:
OR
IFS is used to set field separator (default is while space). The -r option to read command disables backslash escaping
(e.g., \n, \t). This is failsafe while read loop for reading text files.
The while loop statement 96
#!/bin/bash
# set n to 1
n=1
chmod +x while.sh
./while.sh
Sample outputs:
Welcome 1 times.
Welcome 2 times.
Welcome 3 times.
Welcome 4 times.
Welcome 5 times.
The script initializes the variable n to 1, and then increments it by one. The while loop prints out the "Welcome $n
times" until it equals 5 and exit the loop.
#!/bin/bash
n=1
while (( $n <= 5 ))
do
echo "Welcome $n times."
n=$(( n+1 ))
done
#!/bin/bash
file=/etc/resolv.conf
while IFS= read -r line
do
# echo line is stored in $line
The while loop statement 97
echo $line
done < "$file"
chmod +x whilereadfile.sh
./whilereadfile.sh
Sample outputs:
nameserver 127.0.0.1
nameserver 192.168.1.254
nameserver 4.2.2.1
#!/bin/bash
file=/etc/resolv.conf
while IFS= read -r f1 f2
do
echo "field # 1 : $f1 ==> field #2 : $f2"
done < "$file"
Run it as follows:
chmod +x whilereadfields.sh
./whilereadfields.sh
Sample outputs:
Another useful example for reading and phrasing /etc/passwd [1] file using the while loop (readpasswd.sh):
#!/bin/bash
file=/etc/passwd
# set field delimiter to :
# read all 7 fields into 7 vars
while IFS=: read -r user enpass uid gid desc home shell
do
# only display if UID >= 500
[ $uid -ge 500 ] && echo "User $user ($uid) assigned \"$home\"
home directory with $shell shell."
done < "$file"
chmod +x readpasswd.sh
./readpasswd.sh
The while loop statement 98
Sample output:
External Links
• Bash While Loop Example [2]
References
[1] http:/ / www. cyberciti. biz/ faq/ understanding-etcpasswd-file-format/
[2] http:/ / www. cyberciti. biz/ faq/ bash-while-loop/
You can use : special command with → while loop to tests or set an infinite loop or an endless loop. An infinite loop
occurs when the condition will never be met, due to some inherent characteristic of the loop. There are a few
situations when this is desired behavior. For example, the menu driven program typically continue till user selects to
exit their main menu (loop). To set an infinite while loop use:
1. true command - do nothing, successfully (always returns exit code 0)
2. false command - do nothing, unsuccessfully (always returns exit code 1)
3. : command - no effect; the command does nothing (always returns exit code 0)
Syntax
Use : command to set an infinite loop:
#!/bin/bash
while :
do
echo "Do something; hit [CTRL+C] to stop!"
done
#!/bin/bash
while true
do
echo "Do something; hit [CTRL+C] to stop!"
done
#!/bin/bash
while false
do
echo "Do something; hit [CTRL+C] to stop!"
done
#!/bin/bash
while :
do
clear
# display menu
echo "Server Name - $(hostname)"
echo "-------------------------------"
echo " M A I N - M E N U"
echo "-------------------------------"
echo "1. Display date and time."
echo "2. Display what users are doing."
echo "3. Display network connections."
echo "4. Exit"
# get input from the user
read -p "Enter your choice [ 1 -4 ] " choice
# make decision using case..in..esac
case $choice in
1)
echo "Today is $(date)"
read -p "Press [Enter] key to continue..."
readEnterKey
;;
2)
w
read -p "Press [Enter] key to continue..."
readEnterKey
;;
3)
netstat -nat
read -p "Press [Enter] key to continue..."
Use of : to set infinite while loop 100
readEnterKey
;;
4)
echo "Bye!"
exit 0
;;
*)
echo "Error: Invalid option..."
read -p "Press [Enter] key to continue..."
readEnterKey
;;
esac
done
chmod +x menu.sh
./menu.sh
Sample outputs:
Syntax
The until loop continues running commands as long as the item in list continues to evaluate true. Once an item
evaluates false, the loop is exited. The syntax is:
until [ condition ]
do
command1
command2
...
....
commandN
done
Example
Create a shell script called until.sh:
#!/bin/bash
i=1
until [ $i -gt 6 ]
do
echo "Welcome $i times."
i=$(( i+1 ))
done
chmod +x until.sh
./until.sh
Sample outputs:
Welcome 1 times.
Welcome 2 times.
Welcome 3 times.
Welcome 4 times.
Welcome 5 times.
Welcome 6 times.
The until loop statement 102
The loop in the above example initializes the variable i to 1, and then increments and displays out the message until
it equals 6.
The Bash Shell also offer select Loop, the syntax is:
Example
Create a shell script called select.sh:
#!/bin/bash
# Set PS3 prompt
PS3="Enter the space shuttle to get more information : "
chmod +x select.sh
./select.sh
Sample outputs:
/tmp/x.sh
1) columbia 3) challenger 5) atlantis 7) pathfinder
2) endeavour 4) discovery 6) enterprise
Enter the space shuttle name to get more information : 1
columbia selected
Enter the space shuttle name to get more information :
#!/bin/bash
# Set PS3 prompt
PS3="Enter the space shuttle to get quick information : "
echo "--------------"
;;
challenger)
echo "--------------"
echo "Space Shuttle Challenger was NASA's second Space
Shuttle orbiter to be put into service."
echo "--------------"
;;
discovery)
echo "--------------"
echo "Discovery became the third operational orbiter,
and is now the oldest one in service."
echo "--------------"
;;
atlantis)
echo "--------------"
echo "Atlantis was the fourth operational shuttle
built."
echo "--------------"
;;
enterprise)
echo "--------------"
echo "Space Shuttle Enterprise was the first Space
Shuttle orbiter."
echo "--------------"
;;
pathfinder)
echo "--------------"
echo "Space Shuttle Orbiter Pathfinder is a Space
Shuttle simulator made of steel and wood."
echo "--------------"
;;
*)
echo "Error: Please try again (select 1..7)!"
;;
esac
done
chmod +x selectshuttle.sh
./selectshuttle.sh
Sample outputs:
The select loop statement 105
selectshuttle.sh output
You can exiting the → select loop statement either pressing Ctrl+C or by adding the exit option as follows:
#!/bin/bash
# Set PS3 prompt
PS3="Enter the space shuttle to get quick information : "
;;
atlantis)
echo "--------------"
echo "Atlantis was the fourth operational shuttle
built."
echo "--------------"
;;
enterprise)
echo "--------------"
echo "Space Shuttle Enterprise was the first Space
Shuttle orbiter."
echo "--------------"
;;
pathfinder)
echo "--------------"
echo "Space Shuttle Orbiter Pathfinder is a Space
Shuttle simulator made of steel and wood."
echo "--------------"
;;
exit)
echo "Bye!"
break
;;
*)
echo "Error: Please try again (select 1..8)!"
;;
esac
done
Sample output:
Use the break statement to exit from within a → FOR, → WHILE or → UNTIL loop i.e. stop stop loop execution.
Syntax
break
OR
break N
#!/bin/bash
match=$1 # fileName
found=0 # set to 1 if file found in the for loop
# show usage
[ $# -eq 0 ] && { echo "Usage: $0 fileName"; exit 1; }
if [ $f == "$match" ]
then
echo "$match file found!"
found=1 # file found
break # break the for looop
fi
done
chmod +x forbreak.sh
./forbreak.sh /etc/resolv1.conf
./forbreak.sh /etc/resolv.conf
Sample outputs:
#!/bin/bash
# set an infinite while loop
while :
do
read -p "Enter number ( -9999 to exit ) : " n
done
chmod +x whilebreak.sh
./whilebreak.sh
Sample outputs:
...
for i in something
do
while true
do
cmd1
cmd2
[ condition ] && break 2
done
done
....
..
The above break 2 will breaks you out of two enclosing for and while loop.
The continue statement is used to resume the next iteration of the enclosing → FOR, → WHILE or → UNTIL loop.
Syntax
continue
OR
continue n
OR
...
..
for i in something
do
[ condition ] && continue
cmd1
cmd2
done
Using the continue statement 110
..
...
OR
...
..
while true
do
[ condition1 ] && continue
cmd1
cmd2
[ condition2 ] && break
done
..
...
The following two examples assumes that familiarity with MySQL and BIND 9 named servers.
#!/bin/bash
# A sample mysql backup script
# Must be run as the root user
# Written by Vivek Gite
# Last updated on : 23/Aug/2003
# ---------------------------------
# MySQL Login Info
MUSER="admin" # MySQL user
MHOST="192.168.1.100" # MySQL server ip
MPASS="MySQLServerPassword" # MySQL password
# format dd-mm-yyyy
NOW=$(date +"%d-%m-%Y")
# Backupfile path
BPATH=/backup/mysql/$NOW
for db in $DBS
do
# Bakcup file name
Using the continue statement 111
FILE="${BPATH}/${db}.gz"
# Path to named.conf
NAMEDCONF="/var/named/chroot/etc/named.conf"
Command substitution
→ ← Continue Home → Chapter 5 Challenges
statement →
Command substitution is nothing but run a shell command and store it's output to a variable or display back using
echo command. For example, display date and time:
OR
Syntax
You can use the grave accent (`) to perform a command substitution. The syntax is:
`command-name`
OR
$(command-name)
OR
echo -e "List of logged on users and what they are doing:\n $(w)"
Command substitution 113
Sample outputs:
var=$(command-name)
NOW=$(date)
echo $NOW
SERVERNAME=$(hostname)
echo $SERVERNAME
CWD=$(pwd)
cd /path/some/where/else
echo "Current dir $(pwd) and now going back to old dir .."
cd $CWD
Chapter 5 Challenges
→ ← Command substitution Home Chapter 6: Shell Redirection →
file1
file2
[DIR] test/
Total regular files : 7
Total directories : 4
Total symbolic links : 0
Total size of regular files : 2940
• Write a shell script that will count the number of files in each of your sub-directories using the for loop.
• Write a shell script that accepts two directory names as arguments and deletes those files in the first directory
which are similarly named in the second directory.
• Write a shell script to search for no password entries in /etc/passwd and lock all accounts.
• Write a shell program to read two numbers and display all the odd numbers between those two numbers.
Almost all commands produces the output to screen or take input from the keyboard, but in Linux it is possible to
send output to a file or to read input from a file. Each shell command has its own input and outputs. Before a
command is executed, its input and output may be redirected using a special notation interpreted by the shell. For
example, sending output of date command to a file instead of to the screen. Changing the default path of input or
output is called redirection.
stdin 0 Read input from a file (the default is keyboard) cat < filename
stdout 1 Send data to a file (the default is screen). date > output.txt
cat output.txt
You can manipulate the final result by redirecting input and output.
Standard input
→ ← Input and Home → Standard output
Output →
• Standard input is the default input method, which is used by all commands to read its input.
• It is denoted by zero number (0).
• Also known as stdin.
• The default standard input is the keyboard.
• < is input redirection symbol and syntax is:
• For example, you can run cat command as follows to display /etc/passwd on screen:
Standard output
→ ← Standard Home → Standard error
input →
ls
But, you can save the output to a file called output.txt, enter:
ls > /tmp/output.txt
cat /tmp/output.txt
• Please note that /tmp/output.txt file is created if it doesn't exist. And if file /tmp/output.txt file is overwritten if it
exits.
• You can also save your script output to the file:
Standard output 119
Standard error
→ ← Standard Home → Empty file creation →
output
• Standard error is the default error output device, which is used to write all system error messages.
• It is denoted by two number (2).
• Also known as stderr.
• The default standard input is the screen or monitor.
• 2> is input redirection symbol and syntax is:
For example, send find command errors to a file called fileerrors.txt, sothat you can review errors later on, enter:
>newfile.name
• > operator redirects output to a file. If no command given and if file doesn't exist it will create empty file. For
example, create a shell script called tarbackup.sh:
#!/bin/bash
TAR=/bin/tar
# Logfile name
ERRLOG=/tmp/tar.logfile.txt
# Remove old log file and create the empty log file
>$ERRLOG
Notice you can also use touch command for empty file creation:
touch /tmp/newtextfile
chmod +x tarbackup.sh
./tarbackup.sh
All data written on a /dev/null or /dev/zero special file is discarded by the system. Use /dev/null to send any
unwanted output from program/command and syntax is:
command >/dev/null
This syntax redirects the command standard output messages to /dev/null where it is ignored by the shell. OR
command 2>/dev/null
This syntax redirects the command error output messages to /dev/null where it is ignored by the shell. OR
command &>/dev/null
This syntax redirects both standard output and error output messages to /dev/null where it is ignored by the shell.
Example
Try searching user vivek in /etc/passwd file:
grep vivek /etc/passwd && echo "Vivek found" || "Vivek not found"
Sample outputs:
vivek:x:1000:1000:Vivek Gite,,,,:/home/vivek:/bin/bash
Vivek found
To ignore actual output and just display the message, modify your command as follows:
grep vivek /etc/passwd >/dev/null && echo "Vivek found" || "Vivek not
found"
Sample outputs:
Vivek found
Consider the following example from → the exit status chapter. The output of grep "^$username"
$PASSWD_FILE > /dev/null is send to /dev/null where it is ignored by the shell.
#!/bin/bash
# set var
PASSWD_FILE=/etc/passwd
Here documents
← /dev/null discards unwanted output Home → here strings
→
command <<HERE
text1
text2
testN
$varName
HERE
This type of redirection tells the shell to read input from the current source (HERE) until a line containg only word
(HERE) is seen. HERE word is not subjected to variable name, parameter expansion, arithmetic expansion,
pathname expansion, or → command substitution. All of the lines read up to that point are then used as the standard
input for a command. Files are processed in this manner are commonly called here documents.
Example
Use here document feature to give constant text to a command. For example the following command will count the
words for input:
Sample outputs:
But, how do you count lots of lines at a time? Use here document as follows:
wc -w <<EOF
> This is a test.
> Apple juice.
> 100% fruit juice and no added sugar, colour or preservative.
> EOF
Here documents 123
Sample outputs:
16
The <<, reads the shell input typed after the wc command at the PS2 prompts, >) up to a line which is identical to
word EOF.
#!/bin/bash
# run tar command and dump data to tape
tar -cvf /dev/st0 /www /home 2>/dev/null
END_OF_EMAIL
chmod +x tapebackup1.sh
./tapebackup1.sh
Sample outputs:
Subject: Test
From: root <root@www-03.nixcraft.net.in>
Date: 12:57 Am
To: vivek@nixcraft.co.in
The script provides the constant multi-line text input to the mail command.
Here strings
→ ← here documents Home → Redirection of standard error →
command <<<$word
OR
The $word (a shell → variable) is expanded and supplied to the command on its → standard input. The following wc
command will count words from given argument:
Sample outputs:
Sample outputs:
However, with here string you can grep into $var, enter:
grep "nor" <<<$var >/dev/null && echo "Found" || echo "Not found"
Sample output:
Found
echo $var | grep "nor" -q && echo "Found" || echo "Not found"
Sample outputs:
command-name 2>error.log
Find all .profile files in /home directory and log errors to /tmp/error file, enter:
Sample output:
/home/t2/.profile
/home/vivek/ttt/skel/.profile
more /tmp/error
Sample outputs:
./script.sh 2>scripts.err
/path/to/example.pl 2>scripts.err
command-name 2>>error.log
./script.sh 2>>error.log
/path/to/example.pl 2>>error.log
External links
• BASH Shell: How To Redirect stderr To stdout ( redirect stderr to a File ) [1]
• BASH Shell Redirect Output and Errors To /dev/null [2]
• How do I save or redirect stdout and stderr into different files? [3]
References
[1] http:/ / www. cyberciti. biz/ faq/ redirecting-stderr-to-stdout/
[2] http:/ / www. cyberciti. biz/ faq/ how-to-redirect-output-and-errors-to-devnull/
[3] http:/ / www. cyberciti. biz/ faq/ saving-stdout-stderr-into-separate-files/
Redirection of standard output 127
You can also use the > operator to print file, enter:
OR
External links
• BASH Shell: How To Redirect stderr To stdout ( redirect stderr to a File ) [1]
• BASH Shell Redirect Output and Errors To /dev/null [2]
• How do I save or redirect stdout and stderr into different files? [3]
You can append the output to the same file using >> operator, enter:
External links
• BASH Shell: How To Redirect stderr To stdout ( redirect stderr to a File ) [1]
• BASH Shell Redirect Output and Errors To /dev/null [2]
• How do I save or redirect stdout and stderr into different files? [3]
→ ← Redirection of standard output Home → Redirection of both standard error and output
→
You can redirect both stdout and stderr to file using the following syntax:
command-name &>filename
command-name >cmd.log 2>&1
command-name >/dev/null 2>&1
OR
External links
• BASH Shell: How To Redirect stderr To stdout ( redirect stderr to a File ) [1]
• BASH Shell Redirect Output and Errors To /dev/null [2]
• How do I save or redirect stdout and stderr into different files? [3]
You need to use the redirection symbol, >, to send data to a file. For example, my script called ./payment.py generate
output as follows on screen:
./payment.py -a -t net
Sample outputs:
+-+-----------+---------+-------------+
|#| Month | NetRev | Paid Details|
+-+-----------+---------+-------------+
|1| Feb-09| 747.56 | 06-Apr-2009 |
|2| Mar-09| 373.14 | 20-Apr-2009 |
|3| Apr-09| 163.66 | 19-May-2009 |
|4| May-09| 158.18 | 19-Jun-2009 |
|5| Jun-09| 3768.96 | 17-Jul-2009 |
|6| Jul-09| 2150.06 | 21-Aug-2009 |
+-+-----------+---------+-------------+
Use the > redirection symbol, to send data to a file called netrevenue.txt, enter:
Sample outputs:
Writing output to files 130
To enable existing regular files to be overwritten with the > operator set noclobber option as follows:
cat /tmp/test.txt
set +C
echo "Test 123" > /tmp/test.txt
cat /tmp/test.txt
vivek
tom
Jerry
Ashish
Babu
Now, run tr command as follows to convert all lowercase names to the uppercase, enter:
Sample outputs:
VIVEK
TOM
JERRY
ASHISH
BABU
Notice do not use the same file name for standard input and standard output. This will result into data loss and results
are unpredictable.
To sort names stored in output.txt, enter:
However,
→ ← Redirection of both standard error and Home → Assigns the file descriptor (fd) to file for output →
output
Assigns the file descriptor (fd) to file for output 131
File descriptors 0, 1 and 2 are reserved for stdin, stdout and stderr respectively. However, bash shell allows you to
assign a file descriptor to an input file or output file. This is done to improve file reading and writing performance.
This is known as user defined file descriptors.
Syntax
You can assign a file descriptor to an output file with the following syntax:
• where, fd >= 3
Example
Create a shell script called fdwrite.sh:
#!/bin/bash
# Let us assign the file descriptor to file for output
# fd # 3 is output file
exec 3> /tmp/output.txt
# Close fd # 3
exec 3<&-
chmod +x fdwrite.sh
./fdwrite.sh
cat /tmp/output.txt
Sample outputs:
This is a test
Sun Sep 20 01:10:38 IST 2009
→ ← Writing output to files Home → Assigns the file descriptor (fd) to file for input →
Assigns the file descriptor (fd) to file for input 132
• where, fd >= 3.
Example
Create a shell script called fdread.sh:
#!/bin/bash
# Let us assign the file descriptor to file for input
# fd # 3 is Input file
exec 3< /etc/resolv.conf
# Close fd # 3
exec 3<&-
chmod +x fdread.sh
./fdread.sh
→ ← Assigns the file descriptor (fd) to file for output Home → Closes the file descriptor (fd) →
Closes the file descriptor (fd) 133
exec fd<&-
To close fd # 5, enter:
exec 5<&-
Bash supports the following syntax to open file for both reading and writing on file descriptor:
exec fd<>fileName
Example
Create a shell script called fdreadwrite.sh
#!/bin/bash
FILENAME="/tmp/out.txt"
# Opening file descriptors # 3 for reading and writing
# i.e. /tmp/out.txt
exec 3<>$FILENAME
# Write to file
echo "Today is $(date)" >&3
echo "Fear is the path to the dark side. Fear leads to anger. " >&3
echo "Anger leads to hate. Hate leads to suffering." >&3
echo "--- Yoda" >&3
# close fd # 3
exec 3>&-
→ ← Closes the file descriptor (fd) Home → Reads from the file descriptor (fd) →
Reads from the file descriptor (fd) 134
You can use the read command to read data from the keyboard or file. You can pass the -u option to the read
command from file descriptor instead of the keyboard. This is useful to read file line by line or one word at a time.
Syntax
read -u fd var1 var2 ... varN
Example
Create a shell script called readwritefd.sh as follows:
#!/bin/bash
# Let us assign the file descriptor to file for input fd # 3 is Input
file
exec 3< /etc/resolv.conf
# Close fd # 3 and # 4
exec 3<&-
Reads from the file descriptor (fd) 135
exec 4<&-
chmod +x readwritefd.sh
./readwritefd.sh
Sample output:
To view data written to fd # 4 i.e. /tmp/output.txt, use the cat command as follows:
cat /tmp/output.txt
Sample outputs:
Field #1 - nameserver
Field #2 - 192.168.1.254
#!/bin/bash
# Let us assign the file descriptor to file for input fd # 3 is Input
file
exec 3< /etc/resolv.conf
ls -l /proc/$mypid/fd
# Close fd # 3 and # 4
exec 3<&-
exec 4<&-
chmod +x displayfds.sh
./displayfds.sh
Sample output:
#!/bin/bash
# Shell script utility to read a file line line.
FILE="$1"
exec 3<$FILE
while read -u 3 -r line
do
Reads from the file descriptor (fd) 137
echo $line
done
# Close fd # 3
exec 3<&-
chmod +x readfile.sh
./readfile.sh /etc/resolv.conf
→ ← Opening the file descriptors for reading and writing Home → Executes commands and send output to the file descriptor (fd) →
The syntax is as follows to run or execute commands and send output to the file descriptor:
command-name >& fd
./shell-script >& fd
#!/bin/bash
exec 4> /tmp/out.txt
free -m >&4
#!/bin/bash
# get date in dd-mm-yyyy format
NOW=$(date +"%d-%m-%Y")
chmod +x sysinfo.sh
./sysinfo.sh
Sample outputs:
---------------------------------------------------
System Info run @ Sun Sep 20 02:41:43 IST 2009 for vivek-desktop
---------------------------------------------------
****************************
*** Installed Hard Disks ***
****************************
Disk /dev/sda: 1500.3 GB, 1500301910016 bytes
Disk /dev/sdb: 500.1 GB, 500107862016 bytes
Disk /dev/sdc: 500.1 GB, 500107862016 bytes
************************************
*** File System Disk Space Usage ***
************************************
Filesystem Size Used Avail Use% Mounted on
/dev/sdb2 99G 29G 65G 31% /
tmpfs 4.3G 0 4.3G 0% /lib/init/rw
varrun 4.3G 267k 4.3G 1% /var/run
varlock 4.3G 0 4.3G 0% /var/lock
udev 4.3G 2.9M 4.3G 1% /dev
tmpfs 4.3G 361k 4.3G 1% /dev/shm
/dev/sdb5 294G 282G 12G 96% /share
/dev/sdc2 247G 164G 71G 70% /disk1p2
Executes commands and send output to the file descriptor (fd) 140
******************************************
*** Network Device Information [eth1] ***
******************************************
eth1 is not installed
********************************
*** Wireless Device [wlan0] ***
********************************
wlan0 Link encap:Ethernet HWaddr 00:1e:2a:47:42:8d
inet addr:192.168.1.100 Bcast:192.168.1.255
Mask:255.255.255.0
inet6 addr: fe80::21e:2aff:fe47:428d/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:648676 errors:0 dropped:0 overruns:0 frame:0
TX packets:622282 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:465564933 (465.5 MB) TX bytes:310468013 (310.4 MB)
Interrupt:18 Memory:e3000000-e3010000
*************************************
*** All Network Interfaces Stats ***
*************************************
Kernel Interface table
Iface MTU Met RX-OK RX-ERR RX-DRP RX-OVR TX-OK TX-ERR TX-DRP
TX-OVR Flg
lo 16436 0 6784 0 0 0 6784 0 0
0 LRU
vmnet1 1500 0 0 0 0 0 60 0 0
0 BMRU
vmnet3 1500 0 0 0 0 0 60 0 0
0 BMRU
vmnet8 1500 0 0 0 0 0 60 0 0
0 BMRU
wlan0 1500 0 648676 0 0 0 622282 0 0
0 BMRU
Chapter 6 Challenges
→ ← Executes commands and send output to the file descriptor Home Chapter 7: Pipes and Filters
(fd) →
• Write a shell command that associates the file descriptor 2 to a file called log.txt and send fd # 2 to a log.txt
instead of the screen. Then associates fd # 1 with the file associated with the fd # 2.
• Write a shell script to open /etc/passwd file using fd (input) and copy the same to /tmp/passwd.output file using
file descriptor (output).
→ ← Executes commands and send output to the file descriptor Home Chapter 7: Pipes and Filters
(fd) →
144
Linking Commands
← Chapter 7: Pipes and Filters Home → Multiple commands
→
Under bash you can create a sequence of one or more commands separated by one of the following operators:
; command1; Separates commands that are executed in sequence. In this example, pwd is executed only after
command2 date command completes.
date ; pwd
& command arg The shell executes the command in the background in a subshell. The In this example, find command is executed in
& shell does not wait for the command to finish, and the return status is background while freeing up your shell
0. The & operator runs the command in background while freeing up prompt.
your terminal for other work. find / -iname "*.pdf"
>/tmp/output.txt &
&& command1 && command2 is executed if, and only if, command1 returns an exit [ ! -d /backup ] && mkdir -p
command2 status of zero i.e. command2 only runs if first command1 run /backup
successfully.
See → Logical AND section for examples.
|| command1 || command2 is executed if and only if command1 returns a non-zero tar cvf /dev/st0 /home || mail
command2 exit status i.e. command2 only runs if first command fails. -s 'Backup failed'
you@example.com </dev/null
| command1 | Linux shell pipes join the standard output of command1 to the In this example, output of the ps command is
command2 standard input of command2. provided as the standard input to the grep
command
ps aux | grep httpd
Multiple commands
→ ← Linking Commands Home → Putting jobs in background →
You can build a sequences of commands using the ; character (operator) and syntax is:
OR
{ command1; command2 }
This way you can run commands one after the other. The following example, shell scripts display an error message if
sufficient command line arguments are not passed (math.sh):
#!/bin/bash
a=$1
b=$3
op=$2
ans=0
# display usage
# run commands one after the other using ; chracter
[ $# -eq 0 ] && { echo -e "Usage: $0 num1 op num2\n\t $0 1 + 5"; exit
1; }
case $op in
+)
ans=$((( a+b )));;
-)
ans=$((( a-b )));;
/)
ans=$((( a/b )));;
\*|x)
ans=$((( a+b )));;
*)
echo "Unknown operator."
exit 2;;
esac
echo "$a $op $b = $ans"
chmod +x math.sh
./math.sh
./math.sh 1 + 5
./math.sh 10 \* 5
Without ; and && character (operator) joining multiple command the following one liner:
Multiple commands 146
if [ $# -eq 0 ]
then
echo -e "Usage: $0 num1 op num2\n\t $0 1 + 5"
exit 1;
fi
Examples
Use the watch command to monitor temp file (/tmp) system every 5 seconds:
Job Control
• The bash shell allows you to run tasks (or commands) in the background using the facility called job control.
• Job control refers to the ability to selectively stop, suspend the execution of processes and continue (resume) their
execution at a later point.
• A user typically employs this facility via an interactive interface supplied jointly by the system’s terminal driver
and bash.
Putting jobs in background 147
Jobs
• Processes under the influence of a job control facility are referred to as jobs.
• Each job has a unique id called job number.
• You can use the following command to control the job:
• fg - Place job in the foreground.
• bg - Place job in the background.
• jobs - Lists the active jobs on screen.
Background process
• A command that has been scheduled nonsequentially is called background process.
• You can not see the background processes on screen. For example, Apache httpd server runs in background to
serve web pages. You can put your shell script or any command in background.
Foreground process
• A command that you can see the command on screen is called the foreground process.
command &
command arg1 arg2 &
command1 | command2 arg1 &
command1 | command2 arg1 > output &
• The & operator puts command background and free up your terminal.
• The command which runs in background is called a job.
• You can type other command while background command is running.
Example
For example, if you type:
Sample outputs:
[1] 1307
The find command is now running in background. When bash starts a job in the background, it prints a line showing
a job number ([1]) and a process identification number (PID - 1307). A job sends a message to the terminal upon
completion as follows identifying the job by its number and showing that it has completed:
Pipes
→ ← Putting jobs in background Home → How to use pipes to connect programs
→
A shell pipe is a way to connect the output of one program to the input of another program without any temporary
file.
Syntax
command1 | command2
command1 | command2 | commandN
command1 arg1 | command2 arg1 arg2
get_data_command | verify_data_command | process_data_command |
format_data_command > output.data.file
get_data_command < input.data.file | verify_data_command |
process_data_command | format_data_command > output.data.file
• Use the vertical bar (|) between two commands. In this example, send ls command output to grep command i.e.
find out if data.txt file exits or not in the current working directory):
ls | grep "data.txt"
• All → command line arguments (parameters) listed after command name, but before the the vertical bar:
• There is no need to put spaces between command names and vertical bars, it is optional:
ls -al|grep "data.txt"
• However, I recommend putting white spacing between the command names and vertical bars to improve the
readability.
• You can redirect → pipe output to a file (→ output redirection with > symbol):
Examples
Common shell pipe examples:
ls -l | more
who | sort
who | sort > sorted_list.txt
How to use pipes to connect programs 150
who | wc -l
mount | column -t
Case conversion
v="Unix Philosophy"; echo $v | tr '[:lower:]' '[:upper:]'
echo 'tHIs IS A TeSt' | tr '[:upper:]' '[:lower:]'
You can burn an ISO cdrom image using the following syntax:
• The → input < redirection symbol can be used with pipes to get input from a file:
For example, the sort command will get input from /etc/passwd file, which is piped to grep command:
You redirect the standard output of the last command using a pipe with → > or >> redirection symbol. The syntax is:
For example, sort all process memory wise and save the output to a file called memory.txt:
In this example, mysqldump a database backup program is used to backup a database called wiki:
• The mysqldump command is used to backup database called wiki to /tmp/wikidb.backup file.
• The gzip command is used to compress large database file to save the disk space.
• The scp command is used to move file to offsite backup server called secure.backupserver.com.
• All three commands run one after the other.
• A temporary file is created on local disk in /tmp.
• However, using pipes you can join the standard output of mysqldump command to the standard input of gzip
command without creating /tmp/wikidb.backup file:
• You can avoid creating a temporary file all together and run commands at the same time:
Filters
→ ← Why use Home → Chapter 7 Challenges
pipes →
• If a Linux command accepts its input data from the → standard input and produces its output (result) on →
standard output is known as a filter.
• Filters usually works with Linux → pipes.
Syntax
The syntax is:
command1 | command2
command1 file.txt | command2
command1 args < input.txt | command2
Where,
• command2 is a filter command.
Filters 154
Example
In this example, the grep command act as a filter (it will filter out name vivek from its input):
The uniq command is filter, which takes its input from the sort command and passes output as input to uniq
command; Then uniq command output is redirected to "u_sname" file. The grep command is considered as one of
most popular filter under Linux and UNIX like operating systems.
References
[1] http:/ / www. gnu. org/ manual/ gawk/ gawk. html
[2] http:/ / www. gnu. org/ software/ coreutils/ manual/ html_node/ cut-invocation. html
[3] http:/ / www. gnu. org/ software/ grep/
[4] http:/ / www. gnu. org/ software/ gzip/
[5] http:/ / www. gnu. org/ software/ coreutils/ manual/ html_node/ head-invocation. html
[6] http:/ / www. gnu. org/ software/ coreutils/ manual/ html_node/ paste-invocation. html
[7] http:/ / perldoc. perl. org/ perl. html
[8] http:/ / www. gnu. org/ software/ sed/ sed. html
[9] http:/ / www. gnu. org/ software/ coreutils/ manual/ html_node/ sort-invocation. html
[10] http:/ / www. gnu. org/ software/ coreutils/ manual/ html_node/ split-invocation. html
[11] http:/ / sourceware. org/ binutils/ docs-2. 19/ binutils/ strings. html
[12] http:/ / www. gnu. org/ software/ coreutils/ manual/ html_node/ tac-invocation. html
[13] http:/ / www. gnu. org/ software/ coreutils/ manual/ html_node/ tail-invocation. html
[14] http:/ / www. gnu. org/ software/ coreutils/ manual/ html_node/ tee-invocation. html
[15] http:/ / www. gnu. org/ software/ coreutils/ manual/ html_node/ tr-invocation. html
[16] http:/ / www. gnu. org/ software/ coreutils/ manual/ html_node/ uniq-invocation. html
[17] http:/ / www. gnu. org/ software/ coreutils/ manual/ html_node/ wc-invocation. html
Chapter 7 Challenges
→ ← Filters Home Chapter 8: Traps
→
Chapter 8: Traps
Signals
← Chapter 8: Home → What is a Process? →
Traps
• Linux supports both POSIX reliable signals ("standard signals") and POSIX real-time signals.
• A single is nothing but some sort of inter-process communication (techniques for the exchanging data among
multiple threads in one or more processes or commands) in Linux and Unix like operating systems.
• A single is sent to a process or command in order notify an event that occurred.
• For example, while running a command called 'ls -R /, you may hit CTRL+C (or Break) to cancel command
execution. As soon as you hit CTRL+C, a single called SIGINT (2) sent to indicate interrupt from keyboard.
When, SININT sent to ls command, Linux interrupts the process's normal flow of execution. In this example, ls
command get terminated.
• However, you can register a signal handler for CTRL+C and take some sort of action like ignore it or display a
message on the screen when ls command is interrupted by SINGINT.
• You need to use the trap command to catch signals and handle errors under Linux shell scripts.
• You can send various singles to commands and process. For example, to terminate foreground process you can hit
Ctrl+C key combination. To kill background process you can use the kill command and send SIGTERM
(terminate command):
What is a Process?
→ ← Signals Home → How to view Processes →
Linux is a multiuser (multiple users can login to Linux and share its resources) and multitasking operating system. It
means you can run multiple commands and carry out multiple tasks at a time.
ps -C init -o pid=,cmd
Sample outputs:
CMD
1 /sbin/init
Process States
The status of the process which can be one of the following:
1. D (uninterruptible sleep) - Process is sleeping and cannot be bring back until an event such as I/O occurred.
2. R (running) - Process is running or executing.
3. S (sleeping) - Process is not running and is waiting for an event or a → signal.
4. T (traced or stopped) - Process is stopped.
5. Z (zombie or defunct) - Processes marked <defunct> are dead processes (so-called "zombies") that remain
because their parent has not destroyed them properly. These processes will be destroyed by init if the parent
process exits.
ps -C processName -o pid=,cmd,stat
For example, to display states of lighttpd, php-cgi and firefox-bin processes, enter:
ps -C firefox-bin -o pid=,cmd,stat
ps -C lighttpd -o pid=,cmd,stat
ps -C php-cgi -o pid=,cmd,stat
Sample outputs:
CMD STAT
7633 /opt/firefox/firefox-bin Sl
CMD STAT
32082 /usr/sbin/lighttpd -f /etc/ S
32326 /usr/sbin/lighttpd -f /etc/ S
CMD STAT
1644 /usr/bin/php-cgi S
31331 /usr/bin/php-cgi S
31332 /usr/bin/php-cgi S
31538 /usr/bin/php-cgi S
External links
• Linux Kernel Process Management [1]
• Wikipedia:Copy-on-write
• man pages fork(2), top(1), ps(1).
References
[1] http:/ / www. informit. com/ articles/ article. aspx?p=370047& seqNum=2
You need to use the ps command, pstree command, and pgrep command to view a snapshot of the current processes.
ps - View process
To view current process use the ps command:
ps
ps aux | less
ps aux | grep "process-name"
ps aux | grep "httpd"
ps alx | grep "mysqld"
pstree
Sample outputs:
init─┬─acpid
├─apache2───6*[apache2]
├─atd
├─atop
├─avahi-daemon───avahi-daemon
├─bonobo-activati───{bonobo-activati}
├─console-kit-dae───63*[{console-kit-dae}]
├─cron
├─2*[dbus-daemon]
├─dbus-launch
├─dd
├─deluge───5*[{deluge}]
├─dhclient
├─dnsmasq
├─evince───{evince}
├─firefox───run-mozilla.sh───firefox-bin───27*[{firefox-bin}]
├─gconfd-2
├─gdm───gdm─┬─Xorg
│ └─gnome-session─┬─gnome-panel
│ ├─gpg-agent
│ ├─metacity
How to view Processes 160
│ ├─nautilus
│ ├─python
│ ├─seahorse-agent
│ ├─ssh-agent
│ ├─tracker-applet
│ ├─trackerd───2*[{trackerd}]
│ ├─update-notifier
│ └─{gnome-session}
├─gedit
├─6*[getty]
├─gnome-power-man
├─gnome-screensav
├─gnome-settings-───{gnome-settings-}
├─gnome-terminal─┬─bash───pstree
│ ├─bash───ssltx───ssh
│ ├─gnome-pty-helpe
│ └─{gnome-terminal}
├─gvfs-fuse-daemo───3*[{gvfs-fuse-daemo}]
├─gvfs-gphoto2-vo
├─gvfs-hal-volume
├─gvfsd
├─gvfsd-burn
├─gvfsd-trash
├─hald───hald-runner─┬─hald-addon-acpi
│ ├─hald-addon-cpuf
│ ├─hald-addon-inpu
│ └─hald-addon-stor
├─jsvc─┬─jsvc
│ └─jsvc───39*[{jsvc}]
├─klogd
├─lighttpd───2*[php-cgi───4*[php-cgi]]
├─mixer_applet2───{mixer_applet2}
├─mount.ntfs
├─mysqld_safe─┬─logger
│ └─mysqld───10*[{mysqld}]
├─netspeed_applet
├─ntpd
├─pppd───sh───pptpgw
├─pptpcm
├─pulseaudio─┬─gconf-helper
│ └─2*[{pulseaudio}]
├─squid───squid───unlinkd
├─sshproxyd
├─syslogd
├─system-tools-ba
├─thunderbird───run-mozilla.sh───thunderbird-bin───10*[{thunderbird-bin}]
How to view Processes 161
├─udevd
├─vmnet-bridge
├─2*[vmnet-dhcpd]
├─vmnet-natd
├─3*[vmnet-netifup]
├─winbindd───winbindd
├─workrave───{workrave}
├─workrave-applet
└─wpa_supplicant
pgrep -u vivek,krish
External links
• Show All Running Processes in Linux [1]
• ps - Displays The Processes [2]
References
[1] http:/ / www. cyberciti. biz/ faq/ show-all-running-processes-in-linux/
[2] http:/ / www. cyberciti. biz/ tips/ top-linux-monitoring-tools. html#5
Sending signal to Processes 162
You can send various singles to commands / process and shell scripts using the, pkill command, kill command, and
killall command.
kill -l
Sample outputs:
kill -9 1234
OR
OR
killall processName
killall firefox-bin
The above example will kill all users php-cgi process. However, -u option will kill only processes whose effective
user ID is set to vivek:
External links
• Kill process in Linux or terminate a process in UNIX / Linux [1]
• Linux / UNIX killing a process [2]
• Linux logout user or logoff user with pkill command [3]
References
[1] http:/ / www. cyberciti. biz/ faq/ kill-process-in-linux-or-terminate-a-process-in-unix-or-linux-systems/
[2] http:/ / www. cyberciti. biz/ faq/ howto-linux-unix-killing-restarting-the-process/
[3] http:/ / www. cyberciti. biz/ faq/ linux-logout-user-howto/
Terminating Processes
→ ← Sending signal to Processes Home → Shell signal values
→
• Generally, all process terminates on their own. In this example, find command will terminate when it completed
its task:
• You can terminate foreground process by pressing CTRL+C. It will send a TERM single to the process. In this
example, ls -R is running on screen:
ls -R /
• To terminate simply press CTRL+C (hold down CTRL key and press C) to send an in interrupt single to the ls
command.
• To terminate unwanted background process use kill command with -9 single as described in sending signal to
processes section:
• To stop (suspend) a foreground process hit CTRL+Z (hold down CTRL key and press z). To resume the
foreground process use the fg command, enter:
fg jobid
fg 1
fg %
Terminating Processes 165
Example
Create a shell script called phpjail.sh. This script is used to start php service in a jail. This is done to improve Apache
or Lighttpd web server security. This script demonstrates the usage of the pgrep command, pkill commands, and
other skilled you've learned so far.
#!/bin/sh
# A shell script to start / stop php-cgi process.
# Author: Vivek Gite <vivek@gite.in>
# Last updated on June-23-2007.
# ----------------------------------------------
fFCGI=/usr/bin/spawn-fcgi
fIP=127.0.0.1
fPORT=9000
fUSER=phpjail
fGROUP=phpjail
fCHILD=10
fJAILDIR=/phpjail
fPID=/var/run/fcgi.php.pid
fPHPCGI=/usr/bin/php-cgi
start)
Terminating Processes 166
${RM} -f $fPID
else
echo "$0: php-cgi is not running."
fi
;;
status)
# find out if php-cgi is running or not
${PGREP} -u ${fUSER} php-cgi >/dev/null 2>&1
[ $? -eq 0 ] && echo "$0: php-cgi is running at
$fIP:$fPORT" \
|| echo "$0: php-cgi is not running at
$fIP:$fPORT"
;;
*)
# display usage
echo "Usage: $0 {start|stop|status}"
esac
I highly recommend the following two articles which deals with php and web server security:
• Apache2 mod_fastcgi: Connect to External PHP via UNIX Socket or TCP/IP Port [1]
• Lighttpd FasCGI PHP, MySQL chroot jail installation under Debian Linux [2]
References
[1] http:/ / www. cyberciti. biz/ tips/ rhel-fedora-centos-apache2-external-php-spawn. html
[2] http:/ / www. cyberciti. biz/ tips/ howto-setup-lighttpd-php-mysql-chrooted-jail. html
• You must know signal and their values while writing the shell scripts.
• You cannot use (trap) all available signals.
• Some singles can never be caught. For example, the signals SIGKILL (9) and SIGSTOP (19) cannot be caught,
blocked, or ignored.
• The following table is a list of the commonly used signal numbers, description and whether they can be trapped or
not:
1 SIGHUP Hangup detected on controlling terminal or death of controlling process. Also, Terminate the process. Yes
used to reload configuration files for many UNIX / Linux daemons.
3 SIGQUIT Quit from keyboard (Ctrl-\. or, Ctrl-4 or, on the virtual console, the SysRq key) Terminate the process Yes
and dump core.
4 SIGILL Terminate the process and dump core. Illegal instruction. Yes
6 SIGABRT Abort signal from abort(3) - software generated. Terminate the process Yes
and dump core.
kill -l
kill -l SIGTSTP
more /usr/include/linux/signal.h
• While running a script user may press Break or CTRL+C to terminate the process.
• User can also stop the process by pressing CTRL+Z.
• Error can occurred dues to bug in a shell script such as arithmetic overflow.
• This may result into errors or unpredictable output.
• Whenever user interrupts a signal is send to the command or the script.
• Signals force the script to exit.
• However, the trap command captures an interrupt.
• The trap command provides the script to captures an interrupt (signal) and then clean it up within the script.
Syntax
The syntax is as follows
Example
Create a shell script called testtrap.sh:
#!/bin/bash
# capture an interrupt # 0
trap 'echo "Exit 0 signal detected..."' 0
# display something
echo "This is a test"
chmod +x testtrap.sh
./testtrap.sh
Sample outputs:
This is a test
Exit 0 signal detected...
• The first line sets a trap when script tries to exit with status 0.
The trap statement 169
• Then script exits the shell with 0, which would result in running echo command.
• Try the following example at a shell prompt (make sure /tmp/rap54ibs2sap.txt doesn't exits).
• Define a shell variable called $file:
file=/tmp/rap54ibs2sap.txt
rm $file
Sample output:
trap
Sample outputs:
rm $file
This time rm command did not displayed an error. The $file doesn't exist yet. The trap command simply exit
whenever it get 0, 1, 2, 3, or 15 single. Try capturing CTRL+C:
#!/bin/bash
# capture an interrupt # 2 (SIGINT)
trap '' 2
# read CTRL+C from keyboard with 30 second timeout
read -t 30 -p "I'm sleeping hit CTRL+C to exit..."
Sample outputs:
trap - signal
trap - signal1 signal2
file=/tmp/test4563.txt
trap 'rm $file' 1 2 3 15
trap
trap - SIGINT
trap
trap - 1 2 3 15
trap
#!/bin/bash
# Shell script to find out odd or even number provided by the user
# ----
# set variables to an integer attribute
declare -i times=0
declare -i n=0
# increase counter by 1
times=$(( ++times ))
done
# display counter
echo "You played $times times."
exit 0
chmod +x oddoreven.sh
./oddoreven.sh
Sample outputs:
0 is an even number.
Enter number (-9999 to exit) : -9999
Bye!
You played 3 times.
You can use the trap command in shell script as follows. Create a shell script called mainmenu01.sh:
#!/bin/bash
;;
4)
echo "Bye!"
exit 0
;;
*)
echo "Error: Invalid option..."
read -p "Press [Enter] key to continue..."
readEnterKey
;;
esac
done
chmod +x mainmenu01.sh
./mainmenu01.sh
Sample outputs:
→ ← How to clear Home → Use the trap statement to catch signals and handle errors →
trap
Use the trap statement to catch signals and handle errors 174
die(){
echo "An error occurred."
exit 2
}
die
#!/bin/bash
# define var
file="/tmp/data.$$"
# create function
die(){
echo "$@"
exit 2
}
# define die()
die(){
echo "..."
}
The following is an updated shell script from → how to clear a trap section:
Use the trap statement to catch signals and handle errors 175
#!/bin/bash
# Shell script to find out odd or even number provided by the user
# set variables to an integer attribute
declare -i times=0
declare -i n=0
# define function
warning(){
echo -e "\n*** CTRL+C and CTRL+Z keys are disabled. Please enter
number only. Hit [Enter] key to continue..."
}
# if it is -9999 die
[ $n -eq -9999 ] && { echo "Bye!"; break; }
# display result
[ $ans -eq 0 ] && echo "$n is an even number." || echo "$n is an
odd number."
# increase counter by 1
times=$(( ++times ))
done
# display counter
echo "You played $times times."
exit 0
The following example, add a user to the Linux system by updating /etc/passwd file and creating home directory at
/home for user. It traps various single to avoid errors while creating user accounts. If user pressed CTRL+C or script
Use the trap statement to catch signals and handle errors 176
terminated it will try to rollback changes made to system files. Traps are turned on before the useradd command in
shell script, and then turn off the trap after the chpasswd line.
#!/bin/bash
# setupaccounts.sh: A Shell script to add user to the Linux system.
# set path to binary files
ADD=/usr/sbin/useradd
SETPASSWORD=/usr/sbin/chpasswd
USERDEL=/usr/sbin/userdel
# set variables
HOMEBASE=/home
HOMEDIR=""
username=""
# capture 0 2 3 15 signals
# if script failed while adding user make sure we clean up mess from
# /home directory and /etc/passwd file
# catch signals using clean_up_useradd()
trap 'clean_up_useradd' SIGINT SIGQUIT SIGTERM
# get password
read -sp "Enter user password : " password
# Add user
echo "Adding user ${username}..."
${ADD} -s /bin/bash -d ${HOMEDIR} ${username} || { echo "$0: User
addition failed."; exit 3; }
# Set a password
echo "Setting up the password for ${username}..."
#printf "%s|%s\n" $username $password | ${SETPASSWORD} || { echo "$0:
Failed to set password for the user."; exit 3; }
echo "$username:$password" | ${SETPASSWORD} || { echo "$0: Failed to
set password for the user."; exit 3; }
You can run this script as follows: chmod +x setupaccounts.sh ./setupaccounts.sh Sample outputs:
What is a Subshell?
→ ← Use the trap statement to catch signals and handle errors Home → Compound command →
• Whenever you run a shell script, it creates a new process called subshell and your script will get executed using a
subshell.
• A Subshell can be used to do parallel processing.
• If you start another shell on top of your current shell, it can be referred to as a subshell. Type the following
command to see subshell value:
echo $BASH_SUBSHELL
OR
WWWJAIL=/apache.jail
export WWWJAIL
die() { echo "$@"; exit 2; }
export -f die
# now call script that will access die() and $WWWJAIL
/etc/nixcraft/setupjail -d cyberciti.com
• However, environment variables (such as $HOME, $MAIL etc) are passed to subshell.
exec command
# redirect the shells stderr to null
exec 2>/dev/null
What is a Subshell? 179
. script.sh
The dot command allows you to modify current shell variables. For example, create a shell script as follows called
/tmp/dottest.sh:
#!/bin/bash
echo "In script before : $WWWJAIL"
WWWJAIL=/apache.jail
echo "In script after : $WWWJAIL"
chmod +x /tmp/dottest.sh
WWWJAIL=/foobar
echo $WWWJAIL
Sample outputs:
/foobar
/tmp/dottest.sh
echo $WWWJAIL
You should see the orignal value of $WWWJAIL (/foobar) as the shell script was executed in a subshell. Now, try
the dot command:
. /tmp/dottest.sh
echo $WWWJAIL
Sample outputs:
/apache.jail
The value of $WWWJAIL (/apache.jail) was changed as the script was run in the current shell using the dot
command.
→ ← Use the trap statement to catch signals and handle errors Home → Compound command →
Compound command 180
Compound command
→ ← What is a Subshell? Home → exec command →
( list )
( command1; command2 )
{ command1; command2 }
All commands will run but only the output of last pipe is saved to the file. To save output of all of the above
commands to file, enter:
Exec command
→ ← Compound command Home → Chapter 8 Challenges
→
• The exec command is used to replace the current shell with the command without spawning a new process or
subshell.
• The exec command is alos used to assign → the file descriptor fd to filename:
• The exec command is used by "wrapper" scripts. For example, php-cgi can run as cgi program after setting
environment variables or other configuration.
• By using exec, the resources used by the php.cgi shell program do not need to stay in use after the program is
started. The following script can be run using Apache web server [1] and it will speed up php execution:
#!/bin/bash
# Shell Script wrapper to Run PHP5 using mod_fastcgi under Apache 2.2.x
# Tested under CentOS Linux and FreeBSD and 7.x server.
PHP_CGI=/usr/local/bin/php-cgi
# for centos / rhel set it as follows
# PHP_CGI=/usr/bin/php-cgi
export PHP_FCGI_CHILDREN=4
export PHP_FCGI_MAX_REQUESTS=1000
exec $PHP_CGI
References
[1] http:/ / www. cyberciti. biz/ faq/ freebsd-apache-php-mod_fastcgi-tutorial/
Chapter 8 Challenges 182
Chapter 8 Challenges
→ ← exec command Home Chapter 9: Functions →
Chapter 9: Functions
We humans are certainly an intelligent species. We work with others and we depend on each other for common
tasks. For example, you depend on a milkman to deliver milk in milk bottles or cartons. This logic applies to
computer programs including shell scripts. When scripts gets complex you need to use divide and conquer technique.
Shell functions
• Sometime shell scripts get complicated.
• To avoid large and complicated scripts use functions.
• You divide large scripts into a small chunks/entities called functions.
• Functions makes shell script modular and easy to use.
• Function avoids repetitive code. For example, is_root_user() function can be reused by various shell scripts to
determine whether logged on user is root or not.
• Function performs a specific task. For example, add or delete a user account.
• Function used like normal command.
• In other high level programming languages function is also known as procedure, method, subroutine, or routine.
hello
hello Vivek
Sample outputs:
• One line functions inside { ... } must end with a semicolon. Otherwise you get an error on screen:
Above will not work. However, the following will work (notice semicolon at the end):
Displaying functions
→ ← Writing your first shell function Home → Removing functions →
To display defined function names use the declare command. Type the following command at a shell prompt:
declare -F
Sample outputs:
declare -f command_not_found_handle
declare -f genpasswd
declare -f grabmp3
declare -f hello
declare -f mp3
declare -f xrpm
declare -f
OR
declare -f | less
Sample outputs:
command_not_found_handle ()
{
if [ -x /usr/lib/command-not-found ]; then
/usr/bin/python /usr/lib/command-not-found -- $1;
return $?;
else
return 127;
fi
}
genpasswd ()
{
local l=$1;
Displaying functions 185
declare -f functioName
declare -f xrpm
Notice if you just type the declare command with no arguments, then it will list all declared variables and functions.
See also
• declare command
Removing functions
→ ← Displaying Home → Defining functions →
functions
unset -f functionName
unset -f hello
declare
See also
• → unset command
• declare command
Defining functions
→ ← Removing functions Home → Writing functions →
name() {
command1;
command2
}
OR
function name() {
command1;
command2
}
OR
OR
where name is the name of the function, and "command1; command2" is a list of commands used in the function.
You need to replace name with actual function name such as delete_account:
rollback(){
...
}
Defining functions 187
add_user(){
...
}
delete_user(){
...
}
Example
Define a function called mount_nas and umount_nas:
You can type your function at the beginning of the shell script:
#!/bin/bash
# define variables
NASMNT=/nas10
....
..
....
# define functions
function umount_nas(){
/bin/mount | grep -q $NASMNT
[ $? -eq 0 ] && /bin/umount $NASMNT
}
# another function
functiom mount_nas(){
Defining functions 188
command1
command2
}
....
...
### main logic ##
# When you wish to access function, you use the following format:
umount_nas
Writing functions
→ ← Defining functions Home → Calling functions →
function name() {
command list;
}
less /etc/init.d/functions
/path/to/fuctions.sh
OR
source /path/to/fuctions.sh
Writing functions 189
name
name arg1 arg2
#!/bin/bash
TEST="/tmp/filename"
# write delete_file()
function delete_file(){
echo "Deleting $TEST..."
}
Sample output:
To avoid such problems write a function at the start of a script. Also, define all variables at the start of a script:
#!/bin/bash
# define variables at the start of script
# so that it can be accessed by our function
TEST="/tmp/filename"
# call delete_file
delete_file
Calling functions
→ ← Writing Home → Pass arguments into a function
functions →
functioName
For example, define and write a function called yday() to display yesterday's date:
function yday(){
date --date='1 day ago'
}
yday
#!/bin/bash
# write the function
function yday(){
date --date='1 day ago'
}
# invoke the function
yday
#!/bin/bash
# A shell script to backup MySQL database and directories to a nas
server.
# Written by Vivek Gite <vivek@gite.in>
# Last updated on, Feb-2-2007
###############################
# Variables #
###############################
CP=/bin/cp
GTAR=/bin/tar
RSYNC=/usr/bin/rsync
MOUNT=/bin/mount
UMOUNT=/bin/umount
GREP=/bin/grep
AWK=/bin/awk
SED=/bin/sed
CUT=/bin/cut
MYSQL=/usr/bin/mysql
MYSQLADMIN=/usr/bin/mysqladmin
MYSQLDUMP=/usr/bin/mysqldump
GZIP=/bin/gzip
LOGGER=/usr/bin/logger
MAILCMD=/bin/mail
DU=/usr/bin/du
RM=/bin/rm
###############################
# User Defined Functions #
###############################
#
# Purpose: Send warning email.
#
tar_warn_email(){
$LOGGER "$(basename $0) GNU/tar: *** Failed at $(date) ***"
$MAILCMD -s "GNU/TAR Backup Failed" "${WARN_ADMIN_EMAIL_IDS}"<<EOF
GNU/Tar backup failed @ $(date) for $(hostname)
EOF
}
#
# Purpose: Backup file system directories.
#
backup_tar(){
$LOGGER "$(basename $0) GNU/tar: Started at $(date)"
# call function to mount nas device
mount_nas
[ ! -d ${TBAKPATH}/$NOW/ ] && $MKDIR -p ${TBAKPATH}/$NOW/
local path="${TBAKPATH}/$NOW/fs-$(date
+"${TIME_FORMAT}").tar.gz"
$GTAR --exclude "*/proc/*" --exclude "*/dev/*" --exclude
'*/cache/*' -zcvf $path $TAR_SRC_DIRS
[ $? -ne 0 ] && tar_warn_email
# call function to unmount nas device
umount_nas
$LOGGER "$(basename $0) GNU/tar: Ended at $(date)"
}
#
# Purpose: Mount backup nas device.
#
mount_nas(){
[ ! -d $NASMNT ] && $MKDIR -p $NASMNT
$MOUNT | $GREP $NASMNT >/dev/null
[ $? -eq 0 ] || $MOUNT -t cifs //$NASSERVER/$NASUSER -o
username=$NASUSER,password=$NASPASSWORD $NASMNT
}
#
# Purpose: Unmount backup nas device.
#
umount_nas(){
$MOUNT | $GREP $NASMNT >/dev/null
[ $? -eq 0 ] && $UMOUNT $NASMNT
Calling functions 193
}
#
# Purpose: Backup mysql database.
#
mysql(){
$LOGGER "$(basename $0) mysql: Started at $(date)"
local DBS="$($MYSQL -u $MUSER -h $MHOST -p$MPASS -Bse 'show
databases')"
local db=""
local linkname=""
[ ! -d $MBAKPATH/$NOW ] && $MKDIR -p $MBAKPATH/$NOW
for db in $DBS
do
[ "$db" == "sgopenxadserver" ] && continue
local tTime=$(date +"${TIME_FORMAT}")
local FILE="${MBAKPATH}/$NOW/${db}.${tTime}.gz"
$MYSQLDUMP -u $MUSER -h $MHOST -p$MPASS $db | $GZIP -9 >
$FILE
#create latest file link
linkname="${MBAKPATH}/$NOW/${db}.latest"
[ -L $linkname ] && /bin/rm $linkname
/bin/ln -s $FILE $linkname
done
$LOGGER "$(basename $0) mysql: Ended at $(date)"
}
#
# Purpose: Wrapper function to call other functions.
#
backup_mysql(){
mount_nas # call function to mount nas device
mysql
umount_nas # call function to unmount nas device
}
###################################
# Main Script Logic Starts Here #
###################################
case "$1" in
mysql)
backup_mysql
;;
fsbak)
backup_tar
;;
mount)
mount_nas
Calling functions 194
;;
umount)
umount_nas
;;
*)
echo "Usage: $0 {mysql|fsbak|mount|umount}"
echo ""
echo "Use this shell script to backup mysql database
and directories to backup nas server."
esac
You can run this script as follows to make a mysql database backup:
./nas_backup.sh mysql
./nas_backup.sh fsbak
function name(){
arg1=$1
arg2=$2
command on $arg1
}
Where,
1. name = function name.
2. foo = Argument # 1 passed to the function (positional parameter # 1).
3. bar = Argument # 2 passed to the function.
Pass arguments into a function 195
Example
Create a function called fresh.sh:
#!/bin/bash
# write a function
function fresh(){
# t stores $1 argument passed to fresh()
t=$1
echo "fresh(): \$0 is $0"
echo "fresh(): \$1 is $1"
echo "fresh(): \$t is $t"
echo "fresh(): total args passed to me $#"
echo "fresh(): all args (\$@) passed to me -\"$@\""
echo "fresh(): all args (\$*) passed to me -\"$*\""
}
chmod +x fresh.sh
./fresh.sh
Sample outputs:
Example
Create a shell script to determine if given name is file or directory (cmdargs.sh):
#!/bin/bash
file="$1"
# User-defined function
function is_file_dir(){
# $f is local variable
local f="$1"
# file attributes comparisons using test i.e. [ ... ]
[ -f "$f" ] && { echo "$f is a regular file."; exit 0; }
[ -d "$f" ] && { echo "$f is a directory."; exit 0; }
[ -L "$f" ] && { echo "$f is a symbolic link."; exit 0; }
[ -x "$f" ] && { echo "$f is an executeble file."; exit 0; }
}
Run it as follows:
./cmdargs.sh /etc/resolv.conf
./cmdargs.sh /bin/date
./cmdargs.sh $HOME
./cmdargs.sh /sbin
Sample outputs:
Local variable
→ ← Pass arguments into a function Home → Returning from a function →
• By default all variables defined before function names are global to functions.
• You can modify the variables in function and the original values will be lost.
• This can be result into problem. For example, create a shell script called fvar.sh:
#!/bin/bash
d=/apache.jail
function create_jail(){
d=$1
echo "create_jail(): d is set to $d"
}
create_jail "/home/apache/jail"
chmod +x fvar.sh
./fvar.sh
Sample outputs:
local command
• You can create a local variables using the local command and syntax is:
local var=value
local varName
OR
function name(){
local var=$1
command1 on $var
}
#!/bin/bash
# global d variable
d=/apache.jail
# write function
function create_jail(){
# d is only visible to this fucntion
local d=$1
echo "create_jail(): d is set to $d"
}
create_jail "/home/apache/jail"
Sample output:
Example
In the following example:
• The declare command is used to create → the constant variable called PASSWD_FILE.
• The function die() is defined before all other functions.
• You can call a function from the same script or other function. For example, die() is called from is_user_exist().
• All function → variables are local. This is a good programming practice.
#!/bin/bash
# Make readonly variable i.e. constant variable
declare -r PASSWD_FILE=/etc/passwd
#
# Purpose: Display message and die with gicen exit code
#
die(){
local message="$1"
local exitCode=$2
echo "$message"
[ "$exitCode" == "" ] && exit 1 || exit $exitCode
}
#
# Purpose: Find out if user exits or not
#
is_user_exist(){
Local variable 199
local u=$1
grep -qEw "^$u" $PASSWD_FILE && die "Username $u exits."
}
#
# Purpose: Is script run by root? Else die..
#
is_root_user(){
[ "$(id -u)" != "0" ] && die "You must be root to run this script" 2
}
#
# Purpose: Display usage
#
usage(){
echo "Usage: $0 username"
exit 2
}
Syntax
• The return command causes a function to exit with the return value specified by N and syntax is:
return N
Example
Create a shell script called isroot.sh as follows:
#!/bin/bash
# version 1.0
chmod +x isroot.sh
./isroot.sh
Sample outputs:
sudo ./isroot.sh
Sample outputs:
Returning from a function 201
The following is an updated version of the same script. This version → create the constants variables using the
declare command called TRUE and FALSE.
#!/bin/bash
# version 2.0
# define constants
declare -r TRUE=0
declare -r FALSE=1
is_root_user && echo "You can run this script." || echo "You need to
run this script as a root user."
#!/bin/bash
# Variables
domain="CyberCiti.BIz"
out=""
##################################################################
# Purpose: Converts a string to lower case
# Arguments:
# $@ -> String to convert to lower case
##################################################################
function to_lower()
{
local str="$@"
local output
output=$(tr '[A-Z]' '[a-z]'<<<"${str}")
echo $output
}
• You can store all your function in a function files called functions library.
• You can load all function into the current script or the command prompt.
• The syntax is as follows to load all functions:
. /path/to/your/functions.sh
Example
Create a function file called myfunctions.sh:
#!/bin/bash
# set variables
declare -r TRUE=0
declare -r FALSE=1
declare -r PASSWD_FILE=/etc/passwd
##################################################################
# Purpose: Converts a string to lower case
# Arguments:
# $1 -> String to convert to lower case
##################################################################
function to_lower()
{
local str="$@"
local output
output=$(tr '[A-Z]' '[a-z]'<<<"${str}")
echo $output
}
##################################################################
# Purpose: Display an error message and die
# Arguments:
# $1 -> Message
# $2 -> Exit status (optional)
##################################################################
function die()
Shell functions library 203
{
local m="$1" # message
local e=${2-1} # default exit status 1
echo "$m"
exit $e
}
##################################################################
# Purpose: Return true if script is executed by the root user
# Arguments: none
# Return: True or False
##################################################################
function is_root()
{
[ $(id -u) -eq 0 ] && return $TRUE || return $FALSE
}
##################################################################
# Purpose: Return true $user exits in /etc/passwd
# Arguments: $1 (username) -> Username to check in /etc/passwd
# Return: True or False
##################################################################
function is_user_exits()
{
local u="$1"
grep -q "^${u}" $PASSWD_FILE && return $TRUE || return $FALSE
}
You can load myfunctions.sh into the current shell environment, enter:
. myfunctions.sh
OR
. /path/to/myfunctions.sh
#!/bin/bash
# Load the myfunctions.sh
# My local path is /home/vivek/lsst2/myfunctions.sh
. /home/vivek/lsst2/myfunctions.sh
# Display $var1
echo -e "*** Orignal quote: \n${var1}"
chmod +x functionsdemo.sh
./functionsdemo.sh
Sample outputs:
Source command
→ ← Shell functions library Home → Recursive function →
• The source command can be used to load any functions file into the current shell script or a command prompt.
• It read and execute commands from given FILENAME and return.
• The pathnames in $PATH are used to find the directory containing FILENAME. If any ARGUMENTS are
supplied, they become the positional parameters when FILENAME is executed.
• The syntax is as follows:
source functions.sh
source /path/to/functions.sh
source functions.sh WWWROOT=/apache.jail PHPROOT=/fastcgi.php_jail
#!/bin/bash
# load myfunctions.sh function file
source /home/vivek/lsst2/myfunctions.sh
# local variable
quote="He WHO Sees me in all things, and ALL things in me, is never far
from me, and I am never far from him."
# invoke is_root()
is_root && echo "You are a superuser." || echo "You are not a
superuser."
Recursive function
→ ← Source Home → Chapter 9 Challenges
command →
#!/bin/bash
# fact.sh - Shell script to to find factorial of given command line arg
function factorial(){
local i=$1
local f
declare -i i
declare -i f
# display usage
[ $# -eq 0 ] && { echo "Usage: $0 number"; exit 1; }
# call factorial
factorial $1
chmod +x fact.sh
./fact.sh
./fact.sh 2
./fact.sh 5
Sample outputs:
2
120
bash -x ./fact.sh 5
Sample outputs:
Recursive function 207
External links
• Wikipedia:Recursion (computer science)
• GNU C/C++/Fortran [1] Compiler Collection.
References
[1] http:/ / gcc. gnu. org/
Chapter 9 Challenges
→ ← Recursive function Home [[|
→]]
But how do you use the shell Source: http://bash.cyberciti.biz/wiki/index.php?oldid=840 Contributors: Admin
The role of shells in the Linux environment Source: http://bash.cyberciti.biz/wiki/index.php?oldid=847 Contributors: Admin
Getting User Input Via Keyboard Source: http://bash.cyberciti.biz/wiki/index.php?oldid=1185 Contributors: Admin, Dovis
Redirection of both standard error and output Source: http://bash.cyberciti.biz/wiki/index.php?oldid=934 Contributors: Admin
Assigns the file descriptor (fd) to file for output Source: http://bash.cyberciti.biz/wiki/index.php?oldid=936 Contributors: Admin
Assigns the file descriptor (fd) to file for input Source: http://bash.cyberciti.biz/wiki/index.php?oldid=937 Contributors: Admin
Opening the file descriptors for reading and writing Source: http://bash.cyberciti.biz/wiki/index.php?oldid=939 Contributors: Admin
Reads from the file descriptor (fd) Source: http://bash.cyberciti.biz/wiki/index.php?oldid=940 Contributors: Admin
Executes commands and send output to the file descriptor (fd) Source: http://bash.cyberciti.biz/wiki/index.php?oldid=941 Contributors: Admin
Use the trap statement to catch signals and handle errors Source: http://bash.cyberciti.biz/wiki/index.php?oldid=1055 Contributors: Admin
License
Attribution-Noncommercial-Share Alike 3.0 Unported
http:/ / creativecommons. org/ licenses/ by-nc-sa/ 3. 0/