Chinaunix首页 | 论坛 | 博客
  • 博客访问: 3737
  • 博文数量: 3
  • 博客积分: 85
  • 博客等级: 民兵
  • 技术积分: 40
  • 用 户 组: 普通用户
  • 注册时间: 2011-02-12 14:59
文章分类
文章存档

2011年(3)

我的朋友

分类: Python/Ruby

2011-02-12 15:20:54

在 Shell 脚本中经常见到类似 CMD=${0}、RMAN_LOG_FILE=${0}.out 带大括号的语法,它是什么意思?可去参考 Stephen G. Kochan 《Unix Shell Programming, 3rd Edition》一书 15.11 节 Arrays. 其中的语句可直接在 Shell 命令符下去实验。

Arrays

The Korn shell and Bash provide a limited array capability (arrays are not a part of the POSIX standard shell). Bash arrays may contain an unlimited number of elements (subject to memory limitations); Korn shell arrays are limited to 4096 elements. Array indexing in both shells starts at zero. An array element is accessed with a subscript, which is an integer-valued expression enclosed inside a pair of brackets. You don't declare the maximum size of a shell array; you simply assign values to elements as you need them. The values that you can assign are the same as for ordinary variables.

$ arr[O]=hello

$ arr[1]="some text"

$ arr[2]=/users/steve/memos

$

To retrieve an element from an array, you write the array name followed by the element number, enclosed inside a pair of brackets as before. The entire construct must be enclosed inside a pair of curly braces, which is then preceded by a dollar sign.

$ echo ${array[0]}

hello

$ echo ${array[1]}

some text

$ echo ${array[2]}

/users/steve/memos

$ echo $array

hello

$

As you can see from the preceding example, if no subscript is specified, element zero is used.

If you forget the curly braces when performing the substitution, here's what happens:

$ echo $array[1]

hello[1]

$

In the preceding example, the value of array is substituted (hello—the value inside array[0]) and then echoed along with [1]. (Note that because the shell does filename substitution after variable substitution, the shell would attempt to match the pattern hello[1] against the files in your current directory.)

The construct [*] can be used as a subscript to substitute all the elements of the array on the command line, with each element delimited by a single space character.

$ echo ${array[*]}

hello some text /users/steve/memos

$

The construct ${#array[*]} can be used to substitute the number of elements in the array array.

$ echo ${#array[*]}

3

$

Note that the number reported here is the actual number of values stored inside the array, not the largest subscript used to store an element inside the array.

$ array[10]=foo

$ echo ${array[*]} Display all elements

hello some text /users/steve/memos foo

$ echo ${#array[*]} Number of elements

4

$

You can declare an array of integers to the shell simply by giving the array name to typeset -i:

typeset -i data

Integer calculations can be performed on array elements using the ((...)) construct:

$ typeset -i array

$ array[0]=100

$ array[1]=50

$ (( array[2] = array[0] + array[1] ))

$ echo ${array[2]}

150

$ i=1

$ echo ${array[i]}

50

$ array[3]=array[0]+array[2]

$ echo ${array[3]}

250

$

Note that not only can you omit the dollar signs and the curly braces when referencing array elements inside double parentheses, you also can omit them outside when the array is declared to be of integer type. Also note that dollar signs are not needed before variables used in subscript expressions.

The following program, called reverse, reads in up to 4096 lines from standard input and then writes them back out to standard output in reverse order:

$ cat reverse

# read lines to array buf



typeset -i line=0



while (( line < 4096 )) && read buf[line]

do

(( line = line + 1 ))

done



# now print the lines in reverse order



while (( line > 0 )) do

(( line = line - 1 ))

echo "${buf[line]}"

done



$ reverse

line one

line two

line three

Ctrl+d

line three

line two

line one

$

The first while loop executes as long as 4096 or fewer lines have been read and there is more data to be read from standard input (recall the && described at the end of , "Decisions, Decisions").

The following function, cdh, changes the current directory like cd but uses an array to keep a history of previous directories. It allows the user to list the directory history and change back to any directory in it:

$ cat cdh

CDHIST[0]=$PWD # initialize CDHIST[0]



cdh ()

{

typeset –i cdlen i

if [ $# -eq 0 ] # default to HOME with no arguments

then

set -- $HOME

fi



cdlen=${#CDHIST[*]} # number of elements in CDHIST



case "$@" in

-l) # print directory list

i=0

while ((i < cdlen))

do

printf "%3d %s\n" $i ${CDHIST[i]}

((i = i + 1))

done

return ;;

-[0-9]|-[0-9][0-9]) # cd to dir in list

i=${1#-} # remove leading '-'

cd ${CDHIST[i]} ;;

*) # cd to new dir

cd $@ ;;

esac



CDHIST[cdlen]=$PWD

}

$

The CDHIST array stores each directory visited by cdh, and the first element, CDHIST[0], is initialized with the current directory when the cdh file is run:

$ pwd

/users/pat

$ . cdh Define cdh function

$ cdh /tmp

$ cdh –l

0 /users/pat

1 /tmp

$

When the cdh file was run, CDHIST[0] was assigned /users/pat, and the cdh function was defined; when cdh /tmp was executed, cdlen was assigned the number of elements in CDHIST (one), and CDHIST[1] was assigned /tmp. The cdh –l caused printf to display each element of CDHIST (on this invocation, cdlen was set to 2, because elements 0 and 1 of CDHIST contained data).

Note that the if statement at the beginning of the function sets $1 to $HOME if no arguments are passed. Let's try that out:

$ cdh

$ pwd

/users/pat

$ cdh –l

0 /users/pat

1 /tmp

2 /users/pat

$

Well, it worked, but now /users/pat shows up twice in the list. One of the exercises at the end of this chapter asks you to remedy this.

Okay, the most useful feature of cdh is the –n option, which causes it to change the current directory to the one specified in the list:

$ cdh /usr/spool/uucppublic

$ cdh –l

0 /users/pat

1 /tmp

2 /users/pat

3 /usr/spool/uucppublic

$ cdh –1

$ pwd

/tmp

$ cdh –3

$ pwd

/usr/spool/uucppublic

$

We can make cdh replace our cd command by using the fact that alias lookup is performed before built-in commands are executed. So if we create a cd alias to cdh, we can have an enhanced cd. In that case, we have to quote every use of cd in the cdh function to prevent recursion:

$ cat cdh

CDHIST[0]=$PWD # initialize CDHIST[0]

alias cd=cdh



cdh ()

{

typeset –i cdlen i

if [ $# -eq 0 ] # default to HOME with no arguments

then

set -- $HOME

fi



cdlen=${#CDHIST[*]} # number of elements in CDHIST



case "$@" in

-l) # print directory list

i=0

while ((i < cdlen))

do

printf "%3d %s\n" $i ${CDHIST[i]}

((i = i + 1))

done

return ;;

-[0-9]|-[0-9][0-9]) # cd to dir in list

i=${1#-} # remove leading '-'

'cd' ${CDHIST[i]} ;;

*) # cd to new dir

'cd' $@ ;;

esac



CDHIST[cdlen]=$PWD

}

$ . cdh Define cdh function and cd alias

$ cd /tmp

$ cd –l

0 /users/pat

1 /tmp

$ cd /usr/spool

$ cd –l

0 /users/pat

1 /tmp

2 /usr/spool

$

summarizes the various array constructs in the Korn shell and Bash.

Table 15.3. Array Constructs

Construct

Meaning

${array[i]}

Substitute value of element i

$array

Substitute value of first element (array[0])

${array[*]}

Substitute value of all elements

${#array[*]}

Substitute number of elements

array[i]=val

Store val into array[i]


阅读(654) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~