1. Trang chủ >
  2. Công Nghệ Thông Tin >
  3. Kỹ thuật lập trình >

Chapter 8. Writing Korn Shell Scripts

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (5.08 MB, 487 trang )


Korn Shell: Unix and Linux Programming Manual, Third Edition, The

By Anatole Olczak



Table of Contents



Chapter 8. Writing Korn Shell Scripts



Executing Korn Shell Scripts

Let's make a Korn shell script out of the print Hello world command by putting it into a file like this:



$ print "print Hello world" >prhello

Before Korn shell scripts can be executed, they must be made executable by setting the execute and

read bits with the chmod command:



$ chmod 755 prhello

or



$ chmod +rx prhello

Assuming that the current directory is in the search path $PATH, prhello can now be executed by simply

invoking it by name:



$ prhello

Hello world

Korn shell scripts can also be executed by invoking them as the first argument to ksh:



$ ksh prhello

Hello world

Now we can use prhello like any other command. The output can be directed to a file:



$ prhello >p.out

$ cat p.out

Hello world

It can be used with a pipe:



$ prhello | wc

1

2 12

or with command substitution:



$ print "We always say \"$(prhello)\""

We always say "Hello world"

By default, Korn shell scripts are run in a separate environment. This means that variables from the

current environment are not available to Korn shell scripts unless explicitly exported, and variables

defined in Korn shell scripts are not passed back to the parent shell. Just to prove it, here is a

demonstration. The checkvar Korn shell script does just one thing: it prints the value of LOCALVAR.



$ cat checkvar

print "LOCALVAR is set to: $LOCALVAR"

If LOCALVAR is set to something in the current environment, and checkvar is run, we see that

LOCALVAR is not defined:



$ LOCALVAR="This is the original value"

$ checkvar

LOCALVAR is set to:

If we export LOCALVAR, then its value will be available to checkvar:



$ typeset —x LOCALVAR

$ checkvar

LOCALVAR is set to: This is the original value

To show that Korn shell script environments cannot modify variable values in the parent shell, we'll

change checkvar to reassign a value to LOCALVAR.



$ cat checkvar

print "LOCALVAR is set to: $LOCALVAR"

LOCALVAR="This is a new value"

print "The new LOCALVAR is set to: $LOCALVAR"

Now when it is run, LOCALVAR is set to the new value:



$ checkvar

LOCALVAR is set to: This is the original value

The new LOCALVAR is set to: This is a new value

Meanwhile, back in the parent shell, LOCALVAR has not been affected.



$ print $LOCALVAR

This is the original value

If the allexport option is enabled (set –a, or set ?o allexport), variables are automatically exported

when defined. By default, this option is disabled.



Positional Parameters

Positional parameters are special variables used to keep track of arguments to the Korn shell, scripts,

and functions. Positional parameter names contain only digits and cannot be set directly using

variable=value syntax. By default, parameter zero (or $0) is set to the name of the shell, script or

function.



$ print $0

/bin/ksh

The remaining parameters 1 to n are set to each of the arguments passed to the shell, script or function.

For example, if you invoke a Korn shell script called ptest and pass the arguments A, B, and C, then in

the script ptest, $0 would be set to ptest, $1 to A, $2 to B, and $3 to C.



Table 8.1. Positional Parameters

$0



name of script or function or pathname of Korn shell for set



$n



nth argument to script, function, or set



${n}



nth argument to script, function, or set when n is greater than 9



$#



number of positional parameters



$*, $@



all positional parameters separated with a blank



"$*"



all positional parameters enclosed in double quotes



${*:X}



all X to the last positional parameters



"${*:X}"



all X to the last positional parameters enclosed in double quotes



${*:X:n}



n positional parameters beginning with Xth



"${*:X:n}"



n positional parameters beginning with Xth enclosed in double quotes



There are three special Korn shell variables that provide information about the current positional

parameters. The first is $#, and it contains the number of positional parameters. The other two are $@

and $*, and they both contain all the positional parameters. So in the above ptest example, $# would be

3, and both $* and $@ would be A B C. Here is a Korn shell script that manipulates positional

parameters. It displays the name of the current script, the number of positional parameters, and the value

of each of the positional parameters:



$ cat check_params

print "Script name:

$0"

print "Number of args passed: $#"

print "Arguments passed:

$*"



print "Arg 1=$1, Arg 2=$2, Arg 3=$3"

If executed with no arguments, this is the output:



$ check_params

Script name:

check_params

Number of args passed: 0

Arguments passed:

Arg 1=, Arg 2=, Arg 3=

while if executed with the arguments A and B, the output is:



$ check_params A B

Script name:

check_params

Number of args passed: 2

Arguments passed:

AB

Arg 1=A, Arg 2=B, Arg 3=



Modifying Positional Parameters



By default, $0 is set to the name of the shell, script or function. It cannot be set or modified. The

remaining parameters from $1 to $n can be reassigned with the shift command.

The shift command, with no arguments, shifts positional parameters left once, so that $1 takes the value

of $2, $2 takes the value of $3, and so on. The original value of $1 is lost.

Let's change the check_params script so that it shifts the positional parameters left once:



$ cat check_params

print "Script name:

$0"

print "Number of args passed: $#"

print "Arguments passed:

$*"

print "Arg 1=$1, Arg 2=$2, Arg 3=$3"

shift

print "Number of remaining args: $#"

print "Remaining args:

$*"

print "Arg 1=$1, Arg 2=$2, Arg 3=$3"

When we run it again with the arguments A B, we get:



$ check_params A B

Script name:

check_params

Number of args passed:

2

Arguments passed:

AB

Arg 1=A, Arg 2=B, Arg 3=



Number of remaining args:

Remaining args:

B

Arg 1=B, Arg 2=, Arg 3=



1



After the shift command, $1 is set to B and $2 is unset. The original value of $1 is lost.

The positional parameters can be shifted left more than once by providing an integer argument to the

shift command: shift n.

Now let's try something else with positional parameters. Here is a Korn shell script called kuucp. It uses

uucp to copy a file to the public directory on the rnihd system.



$ cat kuucp

PUBDIR=${PUBDIR:?usr/spool/uucppublic}

uucp $1 rnihd!$PUBDIR/$1

print "Copied $1 to rnihd!$PUBDIR/$1"

So instead of typing this long command line:



$ uucp n.out rnihd!/usr/spool/uucppublic/n.out

we can do this:



$ kuucp n.out

and in the script, $1 gets substituted with n.out in both the source and target file arguments. We could

extend this further to be able to uucp files to any system by having a system name given as another

command-line argument. Now $1 is used for the source and target file, and $2 for the remote system

name.



$ cat kuucp

PUBDIR=${PUBDIR:?usr/spool/uucppublic}

uucp $1 $2!$PUBDIR/$1

print "Copied $1 to $2!$PUBDIR/$1"

To send the file msg.c to the uucp public directory on the unisf system, kuucp would be invoked like

this:



$ kuucp msg.c unisf

$1 would be substituted with the msg.c, and $2 with unisf. Notice that the destination directory is taken

from PUBDIR variable. If it's not set, the default uucp public directory is used.



The exit command



In Chapter 2, we learned that Unix programs return an exit status. And that a zero exit status indicates

successful execution, while a non-zero exit status indicates failure. The exit command allows you to

terminate execution from anywhere in a Korn shell script and return an exit value using this format:



exit

or



exit n

where n is the exit status to return. If n is not specified, the exit status of the previous command is used. If

you don't use exit, then scripts finish after the last command is executed.

Take a look at the kuucp script again. What happens if an error occurs? For example, if the file argument

is entered incorrectly, or it doesn't exist? The uucp command will fail, but the status message following

will still get displayed. Here is a good place for exit. It could be used to terminate execution and return a

non-zero exit status if for some reason the uucp command failed. To get the exit status, $? is checked

after uucp is run. If it is non-zero, then we display our own error message and exit. Otherwise, the next

command is executed and the script terminates successfully.



$ cat kuucp

PUBDIR=${PUBDIR:?usr/spool/uucpublic}

uucp $1 $2!$PUBDIR/$1 2>&?/span>

(($? != 0)) && {print "Got uucp error"; exit 1;}

print "Copied $1 to $2!$PUBDIR/$1"

By the way, the 2>&?/span> just traps the uucp error messages. We don't need to see them

anymore, since kuucp is now doing its own error processing. Now when kuucp is run on a

non-existent file, this is what happens:



$ kuucp nofile unisf

Got uucp error

$ print $?

1

The exit command does one more thing. If given at the command prompt, it terminates your login shell.



Top



Korn Shell: Unix and Linux Programming Manual, Third Edition, The

By Anatole Olczak



Table of Contents



Chapter 8. Writing Korn Shell Scripts



The [[...]] Command

The [[...]] command is used to evaluate conditional expressions with file attributes, strings, integers, and

more. The basic format is:



[[expression]]

where expression is the condition you are evaluating. There must be whitespace after the opening

brackets, and before the closing brackets. Whitespace must also separate the expression arguments and

operators. For example, these are incorrect:



[[$X=$Y]]

[[$X = $Y]]

while this is correct:



[[ $X == $Y ]]

Notice that there is white space between $X, $Y, and the = operator.

If the expression evaluates to true, then a zero exit status is returned, otherwise the expression evaluates

to false and a non-zero exit status is returned.

If you are familiar with the test and [...] commands, then you'll recognize that [[...]] is just a new and

improved version of the same commands. It basically functions the same way, except that a number of

new operators are available.



Table 8.2. [[...]] String Operators

–n string



true if length of string is not zero



–o option



true if option is set



–z string



true if length of string is zero



string1 = string2



true if string1 is equal to string2



string1 != string2



true if string1 is not equal to string2



string = pattern



true if string matches pattern



string != pattern



true if string does not match pattern



string1 < string2



true if string1 less than string2



string1 > string2



true if string1 greater than string2



Checking Strings

We could use the [[...]] command to check if a variable is set to a certain value. Here, variable X is

assigned abc, then evaluated in this expression:



$ X=abc

$ [[ $X = abc ]] && print "X is set to abc"

X is set to abc

Using the test and [...] commands, the same command could be written as:



test "$X" = abc && print "X is set to abc"

or



[ "$X" = abc ] && print "X is set to abc"

To check if a variable is set to null, the –z option can be used:



[[ —z $VAR ]] && print "VAR is set to null"

or it could be compared to the null string like this:



[[ $VAR = "" ]] && "VAR is set to null"



Checking Patterns



The Korn shell also lets you compare strings to patterns. We could check if X begins with a 'a' like this:



$ X=abc

$ [[ $X = a* ]] && print "$X matches a*"

abc matches a*

or if it's a three-character string:



$ [[ $X = ??? ]] && print "$X has exactly 3 \

characters"

abc has exactly 3 characters

Using the +([0?]) pattern, we could check if X is set to a number:



$ X=123

$ [[ $X = +([0?]) ]] && print "$X is a number"

123 is a number

Table 8.2 lists the most commonly used [[...]] string operators.



Table 8.3. Some [[...]] File Operators

–a file



true if file exists.



–d file



true if file exists and is a directory.



–f file



true if file exists and is a regular file.



–G file



true if file exists and its group id matches the effective group id of the current process.



–L file



true if file exists and is a symbolic link.



–Ofile



true if file exists and its user id matches the effective user id of the current process.



–r file



true if file exists and is readable.



–s file



true if file exists and its size is greater than zero.



–S file



true if file exists and is a socket.



–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. If file is a directory, then true indicates that the

directory is searchable.



file1 –ef



true if file1 exists and is another name for file2.



file2

file1 –nt



true if file1 exists and is newer than file2.



file2

file1 ?ot



true if file1 exists and is older than file2.



file2



Checking File Attributes

Because manipulating files is so important in programming, the Korn shell provides a whole range of file

operators. The most basic operation to perform on a file is to see if it exists, and that can be done using

the –a operator. This is a new Korn shell file operator. Make sure you don't get it confused with the logical

AND operator used by the test and [...] commands, which is also written as –a.



$ touch tmp

$ [[ —a tmp ]] && print "File tmp exists"

File tmp exists

This only indicates that it exists, but not much else. It may be a directory, or a symbolic link, but using this

operator, that's all we know. If we wanted more information, the –f or ?span class="docEmphStrong">d

operators could tell us if a file existed and was a normal file (–f) or if it was just a directory (–d). Let's try

the ?span class="docEmphStrong">f operator on the tmp file:



$ [[ –f tmp ]] && print "File tmp exists and \

is a regular file"

File tmp exists and is a regular file

If we tried the –d operator on the tmp file, it would evaluate to false, because it isn't a directory:



$ [[ –d tmp ]] && print "File tmp exists and \

is a regular file"

$

While on a directory it would evaluate to true:



$ mkdir tmpdir

$ [[ –d tmpdir ]] && print "Directory tmp exists"

Directory tmp exists

This conditional command checks if $FILE is readable, and if not, prints an error message and exits:



[[ –r $FILE ]]||{ print $FILE not readable; exit 1; }



Xem Thêm
Tải bản đầy đủ (.pdf) (487 trang)

×