Shell
What is Shell
Just like the batch file in windows, but more powerful
Pipes and redirection
Redirecting Output
$ ls -l > lsoutput.txt
Write into isoutput.txt
$ ps >> lsoutput.txt
Append to the file
$ kill -HUP 1234 >killout.txt 2>killerr.txt
Kill the process and sperate the output and error info into different files
$ kill -1 1234 >killouterr.txt 2>&1
Kill the process and write the error info in to the same file as output
Redirecting Input
$ more < killout.txt
Pipes
You can connect processes using the pipe operator ( | ).In Linux, unlike in MS-DOS, processes connected by pipes can run simultaneously and are automatically rescheduled as data flows between them
$ ps | sort > pssort.out
$ ps | sort | more
$ ps –xo comm | sort | uniq | grep -v sh | more
The Shell as a Programming Language
$ for file in *
> do
> if grep -l POSIX $file
> then
> more $file
> fi
> done
Note how the normal $ shell prompt changes to a > when the shell is expecting further input. You can type away, letting the shell decide when you’re finished, and the script will execute immediately.
widl cards
$ ls my_{finger,toe}s
Experienced Linux users would probably perform this simple operation in a much more efficient way,
perhaps with a command such as
$ more `grep -l POSIX *`
or the synonymous construction
$ more $(grep -l POSIX *)
In addition,
$ grep -l POSIX * | more
Creating a script
#!/bin/sh
#first
#This file looks through all the files in the current
#directory for the string POSIX, and then prints the names of
t#hose files to the standard output.
for file in *
do
if grep -q POSIX $file
then
echo $file
fi
done
exit 0
#! characters tell the system that the argument that follows on the line is the program to be used to execute this file. In this case, /bin/sh is the default shell program.
The exit command ensures that the script returns a sensible exit code
Lnux, and UNIX in general, rarely makes use of the filename extension to determine the type of a file
Making a script executable
1. $ /bin/sh first
2. $ chmod +x first
#cp first /usr/local/bin
#chown root /usr/local/bin/first
#chgrp root /usr/local/bin/first
#chmod 755 /usr/local/bin/first
Shell Syntax
Varaibles
You don’t usually declare variables in the shell before using them. Instead, you create them by simply
using them (for example, when you assign an initial value to them). By default, all variables are consid-
ered and stored as strings, even when they are assigned numeric values. The shell and some utilities will
convert numeric strings to their values in order to operate on them as required. Linux is a case-sensitive
system, so the shell considers the variable foo to be different from Foo, and both to be different from FOO.
$ salutation=Hello
$ echo $salutation
Hello
$ salutation=”Yes Dear”
$ echo $salutation
Yes Dear
$ salutation=7+5
$ echo $salutation
7+5
Note how a string must be delimited by quote marks if it contains spaces. In addition, there can’t be any spaces on either side of the equals sign.
$ read salutation
Wie geht’s?
$ echo $salutation
Wie geht’s?
The behavior of variables such as $foo inside quotes depends on the type of quotes you use. If you
enclose a $ variable expression in double quotes, then it’s replaced with its value when the line is exe-
cuted. If you enclose it in single quotes, then no substitution takes place. You can also remove the special
meaning of the $ symbol by prefacing it with a /.
#!/bin/sh
myvar=”Hi there”
echo $myvar
echo “$myvar”
echo ‘$myvar’
echo /$myvar
echo Enter some text
read myvar
echo ‘$myvar’ now equals $myvar
exit 0
Enrironment Varaible
$HOME
$PATH
$PS1
$PS2
$IFS
$0
$#
$$
Parameter Variable
$1,$2,$3
Conditions
The test and [ commond
In practice, most scripts make extensive use of the [ or test command, the shell’s Boolean check
if test -f fred.c
then
...
fi
if [ -f fred.c ]
then
...
fi
Note that you must put spaces between the [ braces and the condition being checked. You can remember this by remembering that [ is just the same as writing test, and you would always leave a space after the test command.
If you prefer putting then on the same line as if, you must add a semicolon to separate the test from the then:
if [ -f fred.c ]; then
...
fi
The condition types that you can use with the test command fall into three types: string comparison, arithmetic comparison, and file conditionals.
String Comparison Result
string1 = string2 True if the strings are equal
string1 != string2 True if the strings are not equal
-n string True if the string is not null
-z string True if the string is null (an empty string)
Arithmetic Comparison Result
expression1 -eq expression2 True if the expressions are equal
expression1 -ne expression2 True if the expressions are not equal
expression1 -gt expression2 True if expression1 is greater than expression2
expression1 -ge expression2 True if expression1 is greater than or equal to
expression2
expression1 -lt expression2 True if expression1 is less than expression2
expression1 -le expression2 True if expression1 is less than or equal to
expression2
! expression True if the expression is false, and vice versa
File Conditional Result
-d file True if the file is a directory
-e file True if the file exists. Note that historically the -e option
has not been portable, so -f is usually used.
-f file True if the file is a regular file
-g file True if set-group-id is set on file
-r file True if the file is readable
-s file True if the file has nonzero size
-u file True if set-user-id is set on file
-w file True if the file is writable
-x file True if the file is executable
Condition structures
if condition
then
statements
else
statements
fi
elif
If you want the echo command to delete the trailing new line, the most portable option is to use the printf command (see the printf section later in this chapter), rather than the echo command. Some shells use echo –e, but that’s not supported on all systems. bash allows echo -n to suppress the new line, so if you are confident your script needs to work only on bash, we suggest using that syntax.
for variable in values
do
statements
done
What would happen if you changed the first line from for foo in bar fud 43 to for foo in “bar fud 43”? Remember that adding the quotes tells the shell to consider everything between them as a single string. This is one way of getting spaces to be stored in a variable.
While
while condition do
statements
done
#!/bin/sh
echo “Enter password”
read trythis
while [ “$trythis” != “secret” ]; do
echo “Sorry, try again”
read trythis
done
exit 0
until
until condition
do
statements
done
In general, if a loop should always execute at least once, use a while loop; if it may not need to execute at all, use an until loop.
case
case variable in
pattern [ | pattern] ...) statements;;
pattern [ | pattern] ...) statements;;
...
esac
Notice that each pattern line is terminated with double semicolons (;;). You can put multiple state-
ments between each pattern and the next, so a double semicolon is needed to mark where one statement
ends and the next pattern begins.
#!/bin/sh
echo “Is it morning? Please answer yes or no”
read timeofday
case “$timeofday” in
yes) echo “Good Morning”;;
no ) echo “Good Afternoon”;;
y ) echo “Good Morning”;;
n ) echo “Good Afternoon”;;
* ) echo “Sorry, answer not recognized”;;
esac
exit 0
It doesn’t look for a best match, just the first match. The default condition often turns out to be the impossible condition, so using * can help in debugging scripts.
#!/bin/sh
echo “Is it morning? Please answer yes or no”
read timeofday
case “$timeofday” in
yes | y | Yes | YES ) echo “Good Morning”;;
n* | N* ) echo “Good Afternoon”;;
* ) echo “Sorry, answer not recognized”;;
esac
exit 0
remember using " | " as or operation
#!/bin/sh
echo “Is it morning? Please answer yes or no”
read timeofday
case “$timeofday” in
yes | y | Yes | YES )
echo “Good Morning”
echo “Up bright and early this morning”
;;
[nN]*)
echo “Good Afternoon”
;;
*)
echo “Sorry, answer not recognized”
echo “Please answer yes or no”
exit 1
;;
esac
exit 0
You must be careful to put the most explicit matches first and the most general match last. This is important
because case executes the first match it finds, not the best match. If you put the *) first, it would always be matched, regardless of what was input.
Lists
The AND List
The AND list construct enables you to execute a series of commands, executing the next command only if all the previous commands have succeeded. The syntax is
statement1 && statement2 && statement3 && ...
#!/bin/sh
touch file_one
rm -f file_two
if [ -f file_one ] && echo “hello” && [ -f file_two ] && echo “ there”
then
echo “in if”
else
echo “in else”
fi
exit 0
The OR list
The OR list construct enables us to execute a series of commands until one succeeds, and then not execute any more. The syntax is as follows:
statement1 || statement2 || statement3 || ...
#!/bin/sh
rm -f file_one
if [ -f file_one ] || echo “hello” || echo “ there”
then
echo “in if”
else
echo “in else”
fi
exit 0
Functions
To define a shell function, simply write its name followed by empty parentheses and enclose the statements in braces:
function_name () {
statements
}
#!/bin/sh
foo() {
echo “Function foo is executing”
}
echo “script starting”
foo
echo “script ended”
exit 0
There is no foward declaration in shell, so defind the function before you use it
Local variable and global variable
#!/bin/sh
sample_text=”global variable”
foo() {
local sample_text=”local variable”
echo “Function foo is executing”
echo $sample_text
}
echo “script starting”
echo $sample_text
foo
echo “script ended”
echo $sample_text
exit 0
Return a value
#!/bin/sh
yes_or_no() {
echo “Is your name $* ?”
while true
do
echo -n “Enter yes or no: “
read x
case “$x” in
y | yes ) return 0;;
n | no ) return 1;;
* )
echo “Answer yes or no”
esac
done
}
echo “Original parameters are $*“
if yes_or_no “$1”
then
echo “Hi $1, nice name”
else
echo “Never mind”
fi
exit 0
Commonds
break
We use break to escape from for while and until
#!/bin/sh
rm -rf fred*
echo > fred1
echo > fred2
mkdir fred3
echo > fred4
for file in fred*
do
if [ -d “$file” ]; then
break;
fi
done
echo first directory starting fred was $file
rm -rf fred*
exit 0
:
The colon command is a null command. It’s occasionally useful to simplify the logic of conditions, being an alias for true. Since it’s built-in, : runs faster than true, though its output is also much less readable.
#!/bin/sh
rm -f fred
if [ -f fred ]; then
:
else
echo file fred did not exist
fi
exit
continue
Just like the continue in C
#!/bin/sh
rm -rf fred*
echo > fred1
echo > fred2
mkdir fred3
echo > fred4
for file in fred*
do
if [ -d “$file” ]; then
echo “skipping directory $file”
continue
fi
echo file is $file
done
rm -rf fred*
exit 0
for x in 1 2 3
do
echo before $x
continue 1
echo after $x
done
The (dot) commond
.
excute the commond in the current sheel
. ./shell_script
echo
eval
foo=10
x=foo
y=’$’$x
echo $y
gives $foo
but
foo=10
x=foo
eval y=’$’$x
echo $y
gives 10
exec
exit n
The exit command causes the script to exit with exit code n
export
#!/bin/sh
echo “$foo”
echo “$bar”
#!/bin/sh
foo=”The first meta-syntactic variable”
export bar=”The second meta-syntactic variable”
export2
The commands set -a or set -allexport will export all variables thereafter.
expr
x=$(expr $x + 1)
Expression Evaluation Description
expr1 | expr2 expr1 if expr1 is nonzero, otherwise expr2
expr1 & expr2 Zero if either expression is zero, otherwise expr1
expr1 = expr2 Equal
expr1 > expr2 Greater than
expr1 >= expr2 Greater than or equal to
expr1 < expr2 Less than
expr1 <= expr2 Less than or equal to
expr1 != expr2 Not equal
expr1 + expr2 Addition
expr1 - expr2 Subtraction
expr1 * expr2 Multiplication
expr1 / expr2 Integer division
expr1 % expr2 Integer modulo
printf
just like the one in C/C++
printf “format string“ parameter1 parameter2 ...
Escape Sequence Description
/“ Double quote
// Backslash character
/a Alert (ring the bell or beep)
/b Backspace character
/c Suppress further output
/f Form feed character
/n Newline character
/r Carriage return
/t Tab character
/v Vertical tab character
/ooo The single character with octal value ooo
/xHH The single character with the hexadecimal value HH
return
set
#!/bin/sh
echo the date is $(date)
set $(date)
echo The month is $2
exit 0
shift
#!/bin/sh
while [ “$1” != “” ]; do
echo “$1”
shift
done
exit 0
trap