Chinaunix首页 | 论坛 | 博客
  • 博客访问: 194897
  • 博文数量: 49
  • 博客积分: 1959
  • 博客等级: 上尉
  • 技术积分: 492
  • 用 户 组: 普通用户
  • 注册时间: 2008-12-08 16:23
文章分类

全部博文(49)

文章存档

2012年(8)

2011年(34)

2008年(7)

分类:

2011-05-18 00:22:20

文件测试
文件测试是编写可靠脚本的一个必要部分。
当if语句出现嵌套时,fi语句总是对应离它最近的if语句。以逐层缩进方式编排的if嵌套语句可以使if语句和fi语句的对应关系看起来更清楚易懂。

#!/bin/sh
file=./testing
if [ -d $file ]
then
        echo "$file is a directory"
elif [ -f $file ]
then
        if [ -r $file -a -w $file -a -x $file ]
        then    # nested if command
                echo "You have read, write, and execute permission on $file,"
        fi
else
        echo "$file is neither a file nor a directory,"
fi

null命令
冒号代表的null命令是shell的一个内置命令,它不做任何事情,只返回退出状态0。
null命令有时被放在if命令后面作为一个占位符,这时if命令不执行实际操作,只需要在then后面放置一条命令,否则,程序会生成报错信息,因为then语句后面必须添加内容。
null命令通常被用作循环命令的参数,其作用是让循环无限地进行下去。
脚本范例
#!/bin/sh
name=Tom
if grep "$name" databasefile > /dev/null 2>&1
then
        :
else
        echo "$1 not found in databasefile"
        exit 1
fi
交互式范例
[root@centos fuhao]# DATAFILE=
[root@centos fuhao]# : ${DATAFILE:=$HOME/db/datafile}
[root@centos fuhao]# echo $DATAFILE
/root/db/datafile
[root@centos fuhao]# : ${DATAFILE:=$HOME/junk}
[root@centos fuhao]# echo $DATAFILE
/root/db/datafile

case命令
case命令是一个多路分支命令,可用来代替if/elif命令。case变量的值与值1、值2等值逐一比较,直至找到与之匹配的值。如果某个值与case变量匹配,程序就执行该值后面的命令,直至遇到双分号,然后跳到词esac后面继续往下执行。如果没有找到与case变量匹配的值,程序就执行默认值*)后面的命令,直至遇到;;或esac。
值*)的功能与if/else条件中else语句的相同。case的值里可以用shell通配符,还可以用竖杠(管道符)对两个值取或。
case的值以单个圆括号终止。
注意:把双分号单独写在一行可以方便对脚本的调试。
双分号用于结束语句块,且控制跳转到esac之后。
如果所有值都不能匹配case表达式,就执行*)后面的命令。
esac语句结束case命令。

#!/bin/sh
# Scriptname: colors
echo -n "Which color do you like?"
read color
case "$color" in
[Bb]l??)
        echo I feel $color
        echo The sky is $color
        ;;
[Gg]ree*)
        echo $color is for trees
        echo $color is for seasick;;
red | orange)   # The vertical bar means "OR"
        echo $color is very warm!;;
*)
        echo No such color as $color;;
esac
echo "Out of case"

here文档常与case命令搭配使用。
可以用here文档生成一个显示在屏幕上的选项菜单,要求用户选择一个菜单项,然后用case命令对照选项集测试用户的输入,以执行相应的命令。

#!/bin/sh
echo "Select a terminal type: "
cat << ENDIT
        1) vt 120
        2) wyse50
        3) sun
ENDIT
read choice
case "$choice" in
1) TERM=vt120
   export TERM
   ;;
2) TERM=wyse50
   export TERM
   ;;
3) TERM=sun
   export TERM
   ;;
esac
echo "TERM is $TERM."

--------循环命令--------

for循环命令在某个对象列表上按指定次数执行命令。
格式
 for 变量 in 词表
 do
   命令(命令组)
 done

#!/bin/sh
# Scriptname: backup
# Purpose:
# Create backup files and store them in a backup directory
dir=/root/fuhao/testing/backupscripts
echo "$dir"
for file in memo[1-5]
do
        if [ -f $file ]
        then
                cp $file $dir/$file.bak
                echo "$file is backed up in $dir"
        fi
done

词表中的$*和$@扩展的结果几乎完全一样,唯一的不同是当它们被括在双引号中时,$*的值是一个字符串,而$@的值则是一组独立的词。

#!/bin/sh
# Scriptname: permx
for file        # Empty wordlist
do
        if [ -f $file -a ! -x $file ]
        then
                chmod +x $file
                echo $file now has execute permission
        fi
done

While对紧跟在它后面的那条命令求值,如果该命令的退出状态为0,就执行循环体内的命令。执行到关键字done后,控制回到循环的顶部,while命令再次检查那条命令的退出状态。循环将一直继续下去,直到while计算的那条命令的退出状态非0为止。该命令的退出状态非0时,程序将从关键字done之后开始执行。
格式
while 命令
do
  命令(命令组)
done

#!/bin/sh
# Scriptname: sayit
echo Type q to quit.
go=start
while [ -n "$go" ]      # Make sure to double quote the variable
do
        echo -n I love you.
        read word
        if [ "$word" = q -o "$word" = Q ]
        then
                echo "I'll always love you!"
                go=
        fi
done
test命令(也是while后面的方括号)的选项-n用来测试字符串是否非空。
只要有分号分隔,就可以把do语句和while命令写在同一行上。

until命令只在它后面的命令失败时(即命令返回非0的退出状态时)才执行循环语句。执行到关键字done时,控制回到循环顶部,until命令再次检查其后那条命令的退出状态。直到until测到那条命令的退出状态变成0为止,循环退出。
格式
 until 命令
 do
   命令(或命令组)
 done

#!/bin/sh
# Scriptname: hour
hour=1
until [ $hour -gt 24 ]
do
  case "$hour" in
  [0-9] |1[0-1]) echo "Good morning!"
        ;;
  12) echo "Lunch time."
        ;;
  1[3-7]) echo "Siesta time."
        ;;
  *) echo "Good night."
        ;;
  esac
  hour=`expr $hour +1`
done

循环控制命令
shift命令指定参数时,将参量列表左移指定的次数;没有给定参数时,shift命令仅把参量列表左移一次。一旦列表被移动,左端那个参数就被永远地删除了。while循环遍历位置参量列表时,经常会用到shift命令。
格式
 shift [n]

#!/bin/sh
# Name: doit
# Purpose: shift through command-line arguments
# Usage: doit [args]
while [ $# -gt 0 ]
do
        echo $*
        shift
done

break命令用于强行退出循环,但不退出程序(退出程序要用exit命令)。break在退出无限循环时很有用。
格式
 break [n]

#!/bin/sh
while true; do
        echo Are you ready to move on\?
        read answer
        if [ "$answer" = Y -o "$answer" = y ]
        then
                break
        else
                ls
        fi
done
echo "Here we are"

continue命令在条件为真时,把控制转回循环的顶部。continue下面的所有命令都被忽略。如果被嵌套在多层循环之内,continue将控制转回最内层循环的顶部。如果给它一个数字作为参数,continue就能将控制转到任一层循环的起点。假定嵌套了3层循环,最外层循环是第3层,中间那层是第2层,最里面那层是第1层循环。
不过,如果给continue命令的数字参数大于循环的层数,就退出整个循环。
格式
 continue [n]

#!/bin/sh
# Scriptname: mailem
# Purpose: To send a list
for name in `cat mail_list`
do
        if [ "$name" = "richard" ];then
                continue
        else
                mail $name < memo
        fi
done

使用嵌套循环时,可以给break和continue命令一个整型的数字参数,让控制可以从内层循环跳到外层循环。

shell可以通过管道或重定向将输入从文件传到循环,也可以通过管道或重定向将输出从循环传到文件。shell将启动一个子shell来处理I/O重定向和管道。
将循环的输出重定向到一个文件
#!/bin/sh
# Program name: numberit
# Put line numbers on all lines of memo
if [ $# -lt 1 ]
then
        echo "Usage: $0 filename " >&2
        exit 1
fi
count=1         # Initialize count
cat $1 | while read line        # Input is coming from file on command line
do
        [ $count -eq 1 ] && echo "Processing file $1... " > /dev/tty
        echo $count $line
        count=`expr $count + 1`
done > tmp$$    # Output is going to a temporary file
mv tmp$$ $1

把循环的输出通过管道传给UNIX命令
#!/bin/sh
for i in 7 9 2 3 4 5
do
        echo $i
done | sort -n

在后台执行循环
#!/bin/sh
for person in bob jim joe sam
do
        mail $person < memo
done &
关键字done后的符号&使得循环在后台运行。

使用exec命令,不需要创建子shell,就能打开或关闭标准输入和标准输出。这样,如果启动循环,循环体内创建的所有变量在循环终止后都还能保留。如果在循环中用了重定向,则循环内创建的所有变量都会消失。
exec命令常被用来打开文件(根据文件名或文件描述符)以供读写。注意:文件描述符0、1和2已预留给标准输入、标准输出和标准错误输出。文件打开后将得到下一个可用的文件描述符。

#!/bin/sh
# Scriptname: speller
# Purpose: Check and fix spelling errors in a file
exec < tmp      # Opens the tmp file
while read line # Read from the tmp file
do
        echo $line
        echo -n "Is this word correct? [Y/N] "
        read answer < /dev/tty # Read from the terminal
        case "$answer" in
        [Yy]*)
                continue;;
        *)
                echo "What is the correct spelling? "
                read word < /dev/tty
                sed "s/$line/$word/g" tmp > error
                mv error tmp
                echo $line has been changed to $word.
        esac
done

IFS和循环
shell的内部字段分隔符(internal field separator, IFS)的值包括空格、制表符和换行符。IFS被那些需要分析词列表的命令(如:read、set和for)用作词(token)分隔符。如果列表使用其他不同的分隔符,用户也可以重新设置IFS。改变IFS的值之前,最好先把它的初始值保存到另一个变量中,这样。一旦需要就可以很方便地把IFS恢复为默认值。

#!/bin/sh
# Scriptname: runit
# IFS is the Internal field separator and defaults to
# spaces, tabs, and newlines.
# In this script it is changed to a colon.
names=Tom:Dick:Harry:John
OLDIFS="$IFS"   # Save the original value of IFS
IFS=":"
for persons in $names
do
        echo Hi $persons
done
IFS="$OLDIFS"   # Reset the IFS to old value
set Jill Jane Jolene    # Set positional parameters
for girl in $*
do
        echo Howdy $girl
done
阅读(1773) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~