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