Bourne Shell scripts Language Dazibao: - All variables are string variables. - Read variable with $ prefix, write without. - Use build-in variables $? (exit code), $#, $0..$9 (argc, argv[]) - Understand strong - '', weak - "" and redirecting - `` quotation. - Use expr function for arithmetics and string manipulation. - Use test for logical operations and comparison. Result is in $?. 1. Comments #!/bin/bash # # first row is telling to the system which shell should be # implemented with this script 2. Constant data in code Strings 'this is $strong quoting' # no substitution "this is $weak quoting" # values substituted `expr 2 + 3` # 5 result redirected $(expr 2 + 3) # 5, with XML flavour 3. Variable data in code All primary types of data - boolean, - bit set, - finite integer, - floating point number are stored as formatted strings (in human readable form). Variables does not require declaration. Newer versions of bash support one-dimensional arrays. (a[3]=Abcd) Structures and Containers are not available. % VAR = "My variable" # create / write % echo $VAR # read % unset $VAR # free memory allocated to $VAR Special variables $? return code of the last command $# number of command line arguments $* whole string of arguments as one string $0 script filename $1 .. $n command line arguments 4. Expressions Expressions are evaluated using expr utility Numeric expressions with integers: (+ - * / %) + plus - minus * multiplication / division % modulo (returns the remainder of an integer division) % expr 18 + 4 String manipulations: (index match length substr) # index: position in string of first character in substring that matches. # substr: print substring, starting position & length specified # length: length of string # 'match' operations similarly to 'grep' a=1234zipper43231 # index: position in string of first character in substring that matches. b=`expr index $a 23` echo Numerical position of first 2 in $a is $b. # substr: print substring, starting position & length specified b=`expr substr $a 2 6` echo Substring of $a, starting at 2 and 6 chars long is $b. # length: length of string b=`expr length $a` echo Length of $a is $b. # 'match' operations similarly to 'grep' b=`expr match $a [0-9]*` echo Number of digits at the beginning of $a is $b. b=`expr match $a '\([0-9]*\)'` echo The digits at the beginning of $a are $b. Strings concatination: % a="Uno"; b="Duo"; c=$a$b; echo $c # UnoDuo % d="Just${c}Between"; echo $d # JustUnoDuoBetween 5. Flow control Test tool --------- Use "test" named tool to evaluate expression to boolean. Result is returned in exit code: 0 - true, 1 - false and is stored in $? special variable. Logical operations with exit codes ! logical NOT && logical AND || logical OR cp file1 $var || exit 1 if [ -e file1 ] && [ -e file2 ] then echo "both files exists" fi String comparison -z string is "null", that is, has zero length -n string is not "null". = is equal to ($a = $b) != is not equal to ($a != $b) \< is less than, in ASCII alphabetical order ($a \< $b) Note that the "<" needs to be escaped. \> is greater than, in ASCII alphabetical order ($a \> $b) Note that the ">" needs to be escaped. Filesystem -e file exists -f file is a regular file -s file is not zero size -d file is a directory -b file is a block device (floppy, cdrom, etc.) -c file is a character device (keyboard, sound card, etc.) -p file is a pipe -L file is a symbolic link -S file is a socket -r file is readable (has read permission) -w file has write permission -x file has execute permission -g group-id flag set on file -u user-id flag set on file -k "sticky bit" set (if user does not own a directory that has the sticky bit set, she cannot delete files in it, not even files she owns) -O you are owner of file -G group-id of file same as yours -t n file descriptor n is open. This usually refers to stdin, stdout, and stderr (file descriptors 0 - 2). f1 -nt f2 file f1 is newer than f2 f1 -ot f2 file f1 is older than f2 f1 -ef f2 files f1 and f2 are links to the same file Integer comparison -eq is equal to ($a -eq $b) -ne is not equal to ($a -ne $b) -gt is greater than ($a -gt $b) -ge is greater than or equal to ($a -ge $b) -lt is less than ($a -lt $b) -le is less than or equal to ($a -le $b) Logical expressions (expression) override normal precedence of the operators ! expression logical not -a logical and -o logical or Operators --------- exit N - exit script with exit code N if test expression then ... fi while test expression until test experssion do do ... ... done done break - use this operator to exit do - done loop continue - use this operator to resume next iteration for vVar in 1 2 4 8 do echo $vVar done Note 1: Use for vVar in *; do ... ;done to iterate in directory of files Note 2: Use seq tool to generate lists seq 5 # (stop) 1 2 3 4 5 seq 3 5 # (start stop) 3 4 5 seq 3 2 7 # (start step stop) 3 5 7 Several operators on the same row should be separated by ; for vVar in Alpha Beta Gamma; do echo $vVar done case $vVar in "$condition1" ) command... ;; "$condition2" ) command... ;; esac Example #!/bin/bash case $1 [a-z] ) echo "Lowercase letter";; [A-Z] ) echo "Uppercase letter";; [0-9] ) echo "Digit";; * ) echo "Punctuation, whitespace, or other";; esac # Allows ranges of characters in [square brackets]. 6. Visibility and encapsulation - Write each function in separate file. - If only script ascript uses function foo, ascript_foo name is recommended for this function. Otherwise anamespace_foo name is good for functions used in more than one script. - Also ugly and useless function implementation was introduced in late versions of Bourne Shell (after 1979). foo () { # Checks if any params. if [ -z $1 ] then echo "No parameters passed to function." return 0 else echo "Param #1 is $1." return 1 fi } foo foo abc ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ How to insert data - from command prompt % read a # now write the value for just created a variable % echo $a % echo # wait for key is pressed - inside script source cat > /etc/resolv.conf <". $PS3 The tertiary prompt, displayed in a select loop. $PS4 The quartenary prompt, shown at the beginning of each line of output when invoking a script with the -x option. It displays as "+". $PWD working directory (directory you are in at the time) $OLDPWD old working directory (previous directory you were in) $DIRSTACK contents of the directory stack (affected by pushd and popd) $PPID the process id (pid) of the currently running process This corresponds to the pidof command $MACHTYPE machine type $HOSTTYPE host type $OSTYPE operating system type $EDITOR the default editor invoked by a script, usually vi or emacs. $IGNOREEOF ignore EOF: how many end-of-files (control-D) the shell will ignore before logging out. $TMOUT If the $TMOUT environmental variable is set to a non-zero value time, then the shell prompt will time out after time seconds. This will cause a logout. $SECONDS The number of seconds the script has been running. $REPLY The default value when a variable is not supplied to read. Also applicable to select menus, but only supplies the item number of the variable chosen, not the value of the variable itself. $SHELLOPTS the list of enabled shell options, a readonly variable $BASH the path to the bash binary itself, usually /bin/bash $BASH_ENV an environmental variable pointing to a bash startup file to be read when a script is invoked ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Binary tools recommended for portable Unix scripts: echo TRUE cp touch cat FALSE mv tar tr ln cmp sed expr rm diff awk test mkdir egrep seq rmdir grep ls sort pwd sleep