免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1172 | 回复: 0
打印 上一主题 下一主题

Unix Shell Scripting Advanced chapter8-chapter10 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-08-14 13:00 |只看该作者 |倒序浏览
chapter8
Functions
program structure
1 interpreter
2 opening comment
3 important variables
4 functions
5 main body of code
定义和调用function
Function是一个可以已经命名的代码段,通过调用它可以运行在程序的任何一个部分
functions 必须先定义,才能使用
形式
function_name()
{
    code block
    ...
}
在程序中调用function的方法
1 直接使用function_name (直接使用功能名可能在看得时候产生误解,如果
funtionname是abc,很难判断abc是functionname还是文件名,alias,可执行文件)

bourneshellscript不支持alias ,bourne again ,c,kornshell支持
---
file=greptest
pause()
{
  echo "hit  to continue:\c"
  read junk
}
echo lines that start with a T:
grep '^T' $file
pause
echo=================
echo blank lines:
grep '^$' $file
echo=================
echo Lines that have two or more a\'s anywhere in them:
grep 'aa' $file
pause
---
Function Parameters
传给function的data,叫做function parameter
一般是从命令行传过去得
ps -f  
上面-f 就是传给ps程序的function parameter.-f 改变了ps命令的输出方式
例子
---   
back_one_file()
{
  cp $1 $backupdir
  echo $1 has been backed up
}
---
$1是一个function parameter。$1是一个变量,但是不是在脚本里头赋值,它是通过在
命令行里输入的
可以通过下面的方式调用
backup_one_file report.txt
backup_one_file logo.out
这里report.txt ,log.out 就是脚本中的$1
可以单独定义的参数有9个 $1到$9
这个限制可以通过使用for循环语句来克服。
注意:不像其他的编程语言,shellscript在function's declaration line里没有关于
function's parameter 的reference
因此在shell script的语法检查,没有检查变量的功能,只能自己检查。也就是说如果
要求输入3个,但是只输入1个,不会报错,只能自己检查是否给fuction充足的参数。
可以通过下面的方法来实现。
有些方便简单的变量已经由shell创建出来可以供我们使用,这样可以方面fuction
parameter的调用
$* 表示所有的参数,即从命令行输入的所有参数都传递到function中
$# 表示从命令行输入到function里的参数的数量(e.g.4),通过这个就可以检查,是否
把足够数量的参数从命令行输入到function里。例如实际有3个,但是只输入了1个。就
会出错误。
可以用test帮助判断
test $# gt 2  就是3个或者更多
for 循环可以被写入用来检查function's command-line里的每一个参数。
---
backup_these_files()
{
  for fname #short for "for fname in $*"
  do
    cp $fname /backup
    echo $fname has been backed up
  done
}
---
back_these_files *.txt *.doc
*.txt是所有以txt结尾的文件
*.doc        doc
shell在运行脚本前会先用通配符*匹配符合的文件,然后输入
function return values
Functions可以返回信息到调用代码的地方
有两种方法
1 output(例如标准输出)
2 exit status
Function output
1 这是Function里的代码块中运行的所有程序输出的(如ls,    echo等)
2 通常这些输出都只是简单的输出到屏幕,但是输出也可以被   发送到下面这些地方
      其他程序      sample_func | wc -l
      一个文件      sample_func > file1
      储存在变量里  output=`sample_func`
Function exit status
1 所有的unxi命令都有一个exit status,包括Functions
2 如果没有在function里定义一个exit status,将会使用  function里最后执行的命令
的exit status
3 exit status可以通过return命令定义。
  如 return 1
     0 是没有错误,〉=1是某种错误信息
     或者一般可以认为0 是true ,1是false
  注意: return 后头必须跟数字,不能用true,或者false代         替。
---
valid_file()
{
   [ ! -r $1 ] && return 1
   grep LOGFILE $1 > /dev/null || return 1
   return 0
}
---
上面代码的exit status可以被用在下面的行为中
   if valid_file /logs/May21.log
   then
   ...
注意。return命令类似于exit命令。但是不应该搞混淆。
      return命令终止当前执行的function
      exit命令终止当前执行的shell,也就是说shell script          被终止并且回
到登陆的shell
      return和exit命令都有一个可选的参数。用一个数字表      示exit status返回
给calling environment
Functions in other files
作为一个程序员,会经常有一些可以经常重复用到的代码。这些代码可能在别的shell
script里。
虽然通常可以通过copy来引用,但是如果想对这段代码进行改进,那么对其他copy此代
码段的脚本都要进行修改。
任何写过的适合重新使用的functions如果在其他的脚本里,并且包括将来要写的脚本里
的functions。可以通过.命令来引用
  如  . /home/user1/libs/script_library1
      . /home/user1/libs/script_library2
      func_from_first_library
      func_from_second_library
case study:the yesno Function
此function 的特点
1 它的parameters都被看作单词“yes/no”风格问题来提问使用  者
2 提出问题,然后读回答
3 问题必须以后面的形式回答,y,Y,yes,YES,Yes,n,N,NO,etc
4 如果给出了一个不合法的回答,function重复步骤2,3。
5 如果回答yes,function返回exit status true(0)  or   "false"(1) ,当回答是no
function可以被如下使用
---
if  yesno Do you really wish to quit now
then
    exit
fi
---
例如下面的如何调用
下面是func_library文件的内容
---
yesno()
{
  while :  这里的:也可以用true因为。都是为了不停循环
  do
     echo "$* (Y/N)? \C"
     read yn junk
     case $yn in
         y|Y|YES|Yes|yes)
             return 0;;  #return TURE
         n|N|no|NO|No)
             retrun 1;;
         *)
             echo please answer yes or no.;;
    esac
  done
}
---
下面是test_yesno
---
. func_library
while true
do
    if yesno Do you really wish to quit now
    then
         exit
    fi
done
---
上面的. func_library的意思是func_library脚本里的functions都可以被当前的脚本
test_yesno调用,如同使用自己的function一样。
chapter9
command-line Parameters
任何unix命令可以经由命令行收到参数,不论命令是否使用这些参数。
这些命令行参数通过$1-$9这9个变量来传给shell script
变量$*,$#的使用方法和在functions里的一样
如paramtest
---
if [ "$1" ]
then
    echo Parameter number 1 is \"$1\"
else
    echo Parameter number1 was not set
fi
if [ "$2" ]
then
    echo Parameter number 2 is \"$2\"
else
    echo Parameter number 2 was not set
fi
if [ "$3" ]
then
    echo Parameter number 3 is \"$3\"
else
    echo Parameter number 3 was not set
fi
---
用双引号把test命令的参数括起来,可以减少错误可能性
下面是用forloop来传参数
---
count=1
for p
do
   echo Parameter number $count is \"$p\"
   count=`expr $count + 1`
done
---
function的$1,$2和shellscript的$1和$2是不一样的。
---
do_nothing()
{
  echo the function params are $1 and $2
}
do_nothing xxx yyy
echo the shell script params are $1 and $2
---
为了保证不把shellscript和functions的$1,$2弄混,可以给他们定义一个变量 如
ave=$1,sta=$2类似
advanced command-line control
可以通过shift命令,来单独引用超过$1-$9的更多的命令行的参数。
当使用shift的时候
1 $1原来的value丢失。(所以确保你已经使用过这个参数或者  已经把它储存在其他变
量中 e.g. first=$1)
2 $1 在用shift后指向是第二个参数的值
  $2                    三个
  $3                    四
  一直到$9 指向第10个参数
如 shifttest
---
print_parms()
{
   count=1
   for p
   do
      echo Parameter number $count is \"$p\"
      count=`expr $count + 1`
   done
}
print_params $*
echo SHIFTING!
shift
print_parms $*
---
3 也可以定义shift shell script的参数,决定要shift多少个 shell script 参数
   如shift 4 在转换后,$1将是原来的$5,$2是原来的$6,依   次类推  
Using set --
set--是另一个命令行参数调整命令
虽然不可能在脚本里设置一个单独命令行参数(individual command-line parameter)
($1...$9是只读的)。但是可以通过使用set - 构架整体的设置他们。
如 set -- file1.txt fred
file1.txt里面是希望shell使用的命令行参数
此时$1设置为file1.txt,$2设置为fred
set 通常使用反引号
如  set -- `who | grep fred`
如果fred 登陆则shell的命令行参数将被设置为`who | grep fred`的输入内容
如下例子
---
echo $*
set -- `ls`
echo $*
---
set在设置默认命令行参数的时候非常有用。当用户忘记设置时可以用这个命令修改
---
if [ $# = 0 ]
then
    set -- `who | grep mvirtue`
fi
echo $1 is logged in on $2
---
上面的脚本在运行时如果输入命令行参数,如sh % abc则$#为非0,if语句不运行直接运
行echo命令。如果没有输入命令行参数,sh % 。则会运行if语句的命令,set $1,$2的
内容为who|grep mvirtue的输出。当然$3,$4,也有被设置,但是脚本中并没有使用。
---
if [ $# = 0 ]
then
    set -- `who | grep mvirtue`
fi
echo $1 is logged in on $2
shift 2
echo since $*
---
$3,$4在shift后值变为$1,$2
USING IFS
通常在设置命令行参数的时候使用set --。这些参数被空格或者tabs分割开。有时这样
分割方式开并不是我们需要的方式
可以使用IFS变量(internal field separator)去指定用来分隔开每一个命令行参数的
符号
如 使用 IFS = |
   设置命令行参数变为
   set -- Parameter 1 | Parameter 2|Parameter 3
---
if [ $# = 0 ]
then
    IFS=:
    set -- `grep mvirtue /etc/passwd`
fi
echo Home dir for $1 is $6
echo $*
---
Usage messages
绝大部分的unix命令都有usage message
一组文本行可以显示当用户不正确定义了命令行参数
比如如果程序需要4个参数,但是只输入2个参数,则会产生usage message,如果只需要
1个参数,但是输入了3个参数也同样会产生usage message,或者需要-x,-t 参数,但
是给了一个-y参数,仍然会产生usage message
通过usage message可以快速帮助用户找到给命令输入正确的参数的方式
如 usage: grep [OPTION]... PATTERN [FILE]...
[]表示参数时可选的
推荐如果脚本会经常或者被很多人使用,应该为它创建usage message。
---
if [ $# -lt 2 ]
then
    echo Usage : myscript username filename ...
    exit 2
fi
---
exit 2  数字2 只是用来区分其他输入错误的exit status,可以随意设置值,也可以一
样。但是有区分,更有利于排错。
注意。usage message也应该输出到Standard Error。
      这样可以通过添加 1〉&2 到echo命令结尾来实现。
下面的方法可以让usage message更灵活。假设脚本叫做myscript,再一步假设他被cp或
者linked到其他地方并且使用了不同的文件名。这是非常令人烦恼的事情去仍然记得
usage message和这个脚本仍然相关。(在linked scripts的情况下记住实际上是不可能
的)
有一个解决这种问题的办法。用特殊的变量$0 记录脚本从命令行设置的名字
因此,可以简单的替换$0参数用来改变usage message中脚本的名字

echo Usage: $0 username filename ... 1>&2
注意:$0 不能被shift 。$1-$9可以通过shift命令改变,但是      $0 不可以用shift
命令改变变量值
用户经常可以看到usage message 消息类似如下。$0是一个绝对路径
Usage: /usr/local/bin/myscript username filename ...
上面的绝对路径可以通过basename来补救。但是这样并不十分灵活
echo Usage: `basename $0` username filename ... 1>&2
chapter 10
advanced scripting
debugging
有时脚本可能不能正常工作,并且它的问题并不是很明显。像这种情况就有必要使用
Bourne shell 内嵌的简单debugging功能
sh 使用-x选项来运行一个脚本(sh -x myscript),脚本会在运行每一行前ECHO每一条
命令行
    并且所有的特殊字符(像通配符,变量替换等)在命令行显示前,已经被shell运行
过,也就是已经是确定值不再是变量。

default values for variables
我们经常会写下面的脚本
  if [ -z "$var1" ] #test if var1 is not set
  then
      var1="some default value"
  fi
可以用下面的方式代替
${var1:="some default value"}
上面的命令有一个问题,在命令行,some default value 会被认为是程序的名称
所以也可以用下面的方式来实现
:${var1:="some default value"}
or
var2=${var1:="some default value"}
---
var1="initial value"
:${var1:=hello}
echo var1 is set to $var1
---
temporary files
who > /tmp/who_results
在有些情况下,脚本可能被多个人同时运行,这时相同的temp文件有可能被这些人同时
使用。(这种情况比较明显的是在CGI 编程中)
这就会产生一些问题,有可能一些用户正在写入,而另一些用户可能就把temp文件删掉
了。
解决这个问题的难点就是如何产生一个文件名,这个文件名的可以保证对应单独的脚本
实例。
解决方法是使用$$变量。$$包含当前shell的process ID(运行脚本的shell)
$$可以被用来当作文件名或者文件名的一部分。
---
tmpfile=/tmp/myscript.$$
who > $tmpfile
...
rm $tmpfile
---
preventing abnormal termination
我们都大都熟悉杀掉一个进程是使用kill命令
kill  procID
有办法可以当用kill命令把脚本进程杀死时,让脚本进行一些动作。
kill的机制
当一个进程在被杀掉的时候,实际上是接受一个signal,如果进程没有设计来怎么处理
这个信号,那么这个进程会简单的终止(aborts)
可以编出一个脚本(实际上可以是任何程序)可以当接收到signals是进行一些有意义的
行为
有三种可能的原因我们需要处理signals
1 阻止程序终止(简单的忽略掉signal)
2 退出程序时,同时运行一些有意义的行为-如删除临时文件,储存系统为一个已知的状
态(可能在退出时改变连接的数据库的状态为正常),等
3 有可能让程序当收到一些特定的signal时,在退出前运行一些自定义的行为
  可以设计让shell在接到一些signal时 通知正在使用脚本的人。
不同版本的unix也可能有一些区别。这里有超过20种可能的signals 可以被程序收到。
大部分都很少使用。但是下面的会被经常使用到。
1(SIGHUP,HANG-UP 缩写)当用户的终端断开连接或者登陆的shell终止(modem挂起,  
telnet 会话中断)发生
2 (SIGINT)当用户在键盘上按中断“interrupt”键时产生 ,通常是ctrl-c
3 (SIGQUIT)当用户在键盘上按“quit”键的时候产生,通常是ctrl-\
15 (SIGTERM)当unix正在关机时产生,或者process被手动killed
两个其他signals,SIGUSER1,SIGUSER2(10 and 12 on linux)有利于开发人员在他们的
程序里自定义进程
注意: 任何signal也许被发送到进程用来kill program
       kill -10 12345
        任何程序的任何进程都不能处理signal9(SIGKILL) -9 可以杀掉任何进程,没  
      有办法让进程不被关闭
为了处理signal,脚本应该包含一个如下命令格式的trap命令(通常是在脚本的开头部分
trap命令除非接到signal否则不会运行,所以放在开头)
  如    trap command signal ...
例子
trap ls 1 2
上面的语句会在脚本运行接到1,2信号的时候,暂停正在运行的脚本,运行ls的输出,
然后接着运行脚本正在运行的内容。使用“”可以让程序不做任何事情
上面的命令定义的内容,可以使用function的名字和想在接到信号时使用的参数
---
graceful_exit()
{
   echo "Exiting ,please wait ..."
   #clean up temp files ,etc
   exit $1
}
  trap "graceful_exit 2“ 1 2 15
---
trap "ls -C" 1 2
echo this is line 1
sleep 1
echo this is line 2
sleep 1
echo this is line 3
sleep 1
echo this is line 4
sleep 1
echo this is line 5
sleep 1
echo this is line 6
sleep 1
echo this is line 7
sleep 1
echo this is line 8
sleep 1
echo this is line 9
sleep 1
echo this is line 10
sleep 1
---


本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/29141/showart_359811.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP