Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Cooper M.Advanced bash-scripting guide.2002.pdf
Скачиваний:
13
Добавлен:
23.08.2013
Размер:
916.67 Кб
Скачать

Advanced Bash−Scripting Guide

It is even possible to combine a Bash script and Perl script within the same file. Depending on how the script is invoked, either the Bash part or the Perl part will execute.

Example 34−5. Bash and Perl scripts combined

#!/bin/bash

# bashandperl.sh

echo "Greetings from the Bash part of the script."

# More Bash commands may follow here.

exit 0

#End of Bash part of the script.

#=======================================================

#!/usr/bin/perl

# This part of the script must be invoked with −x option.

print "Greetings from the Perl part of the script.\n";

#More Perl commands may follow here.

#End of Perl part of the script.

bash$ bash bashandperl.sh

Greetings from the Bash part of the script.

bash$ perl −x bashandperl.sh

Greetings from the Perl part of the script.

34.3. Tests and Comparisons: Alternatives

For tests, the [[ ]] construct may be more appropriate than [ ]. Likewise, arithmetic comparisons might benefit from the (( )) construct.

a=8

 

 

# All of the comparisons below are equivalent.

 

test "$a" −lt 16 && echo "yes, $a < 16"

# "and list"

/bin/test "$a" −lt

16 && echo "yes, $a < 16"

 

[ "$a" −lt 16 ] &&

echo "yes, $a < 16"

 

[[ $a −lt 16 ]] &&

echo "yes, $a < 16"

# Quoting variables within

(( a < 16 )) && echo "yes, $a < 16"

# [[ ]] and (( )) not necessary.

city="New York"

# Again, all of the comparisons below are equivalent.

test "$city" \< Paris && echo "Yes, Paris is greater than $city" # Greater ASCII order. /bin/test "$city" \< Paris && echo "Yes, Paris is greater than $city"

[

"$city" \< Paris ] && echo "Yes, Paris is greater than $city"

 

[[ $city < Paris ]] && echo "Yes, Paris is greater than $city"

# Need not quote $city.

#

Thank you, S.C.

 

 

 

 

34.3. Tests and Comparisons: Alternatives

303

Advanced Bash−Scripting Guide

34.4. Optimizations

Most shell scripts are quick 'n dirty solutions to non−complex problems. As such, optimizing them for speed is not much of an issue. Consider the case, though, where a script carries out an important task, does it well, but runs too slowly. Rewriting it in a compiled language may not be a palatable option. The simplest fix would be to rewrite the parts of the script that slow it down. Is it possible to apply principles of code optimization even to a lowly shell script?

Check the loops in the script. Time consumed by repetitive operations adds up quickly. Use the time and times tools to profile computation−intensive commands. Consider rewriting time−critical code sections in C, or even in assembler.

Try to minimize file i/o. Bash is not particularly efficient at handling files, so consider using more appropriate tools for this within the script, such as awk or Perl.

Try to write your scripts in a structured, coherent form, so they can be reorganized and tightened up as necessary. Some of the optimization techniques applicable to high−level languages may work for scripts, but others, such as loop unrolling, are mostly irrelevant. Above all, use common sense.

34.5. Assorted Tips

To keep a record of which user scripts have run during a particular sesssion or over a number of sessions, add the following lines to each script you want to keep track of. This will keep a continuing file record of the script names and invocation times.

# Append (>>) following to end of each script tracked.

date>>

$SAVE_FILE

#Date and time.

echo $0>> $SAVE_FILE

#Script name.

echo>>

$SAVE_FILE

#Blank line as separator.

#Of course, SAVE_FILE defined and exported as environmental variable in ~/.bashrc

#(something like ~/.scripts−run)

The >> operator appends lines to a file. What if you wish to prepend a line to an existing file, that is, to paste it in at the beginning?

file=data.txt

title="***This is the title line of data text file***"

echo $title | cat − $file >$file.new

#"cat −" concatenates stdout to $file.

#End result is

#+ to write a new file with $title appended at *beginning*.

Of course, sed can also do this.

A shell script may act as an embedded command inside another shell script, a Tcl or wish script, or even a Makefile. It can be invoked as as an external shell command in a C program using the system() call, i.e., system("script_name");.

34.4. Optimizations

304

Advanced Bash−Scripting Guide

∙ Put together files containing your favorite and most useful definitions and functions. As necessary, "include" one or more of these "library files" in scripts with either the dot (.) or source command.

#SCRIPT LIBRARY

#−−−−−− −−−−−−−

#Note:

#No "#!" here.

#No "live code" either.

#Useful variable definitions

ROOT_UID=0

#

Root has $UID 0.

E_NOTROOT=101

#

Not root user error.

MAXRETVAL=256

# Maximum (positive) return value of a function.

SUCCESS=0

 

 

FAILURE=−1

 

 

# Functions

 

 

Usage ()

# "Usage:" message.

{

 

 

if [ −z "$1" ]

# No arg passed.

then

 

 

msg=filename

 

 

else

 

 

msg=$@

 

 

fi

 

 

echo "Usage: `basename $0` "$msg""

}

 

 

Check_if_root ()

# Check if root running script.

{

# From "ex39.sh" example.

if [ "$UID" −ne "$ROOT_UID" ]

then

 

 

echo "Must be root to run this script."

exit $E_NOTROOT

 

 

fi

 

 

}

 

 

CreateTempfileName ()

# Creates a "unique" temp filename.

{

# From "ex51.sh" example.

prefix=temp

 

 

suffix=`eval date +%s`

 

Tempfilename=$prefix.$suffix

}

 

 

isalpha2 ()

# Tests whether *entire string* is alphabetic.

{

# From "isalpha.sh" example.

[ $# −eq 1 ] || return $FAILURE

case $1 in

*[!a−zA−Z]*|"") return $FAILURE;; *) return $SUCCESS;;

34.4. Optimizations

305

Advanced Bash−Scripting Guide

esac

# Thanks,

S.C.

}

 

 

abs ()

 

# Absolute value.

{

 

# Caution: Max return value = 256.

E_ARGERR=−999999

 

if [

−z "$1" ]

# Need arg passed.

then

 

 

return $E_ARGERR

# Obvious error value returned.

fi

 

 

if [

"$1" −ge 0 ]

# If non−negative,

then

 

#

absval=$1

# stays as−is.

else

 

# Otherwise,

let "absval = (( 0 − $1 ))"

# change sign.

fi

 

 

return $absval

}

∙ Use special−purpose comment headers to increase clarity and legibility in scripts.

##

Caution.

 

 

rm −rf *.zzy ##

The "−rf" options to "rm" are very dangerous,

 

##+

especially with wildcards.

#+ Line continuation.

 

#

This is line 1

 

 

#+

of a multi−line

comment,

 

#+

and this is the

final line.

 

#*

Note.

 

 

#o

List item.

 

 

#> Another point of view.

 

while [ "$var1" !=

"end" ]

#> while test "$var1" != "end"

Using the $? exit status variable, a script may test if a parameter contains only digits, so it can be treated as an integer.

#!/bin/bash

SUCCESS=0

E_BADINPUT=65

test "$1" −ne 0 −o "$1" −eq 0 2>/dev/null

#An integer is either equal to 0 or not equal to 0.

#2>/dev/null suppresses error message.

if [ $? −ne "$SUCCESS" ] then

echo "Usage: `basename $0` integer−input" exit $E_BADINPUT

fi

let "sum = $1 + 25" echo "Sum = $sum"

# Would give error if $1 not integer.

# Any variable, not just a command line parameter, can be tested this way.

34.4. Optimizations

306