`
xielingjiang
  • 浏览: 33947 次
  • 性别: Icon_minigender_1
  • 来自: 上海
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

Unix系列shell程序编写(下)

阅读更多
Until语句
  While语句中,只要某条件为真,则重复执行循环代码,until语句正好同while相反,该语句使循环代码重复执行,直到遇到某一条件为真才停止。

Until语句的结构如下:
until command
  do
    command
    command
    … …
  done

  可以用until语句替换上面备份程序的while语句,完成同样的功能:

until [ $ANS != Y -a $ANS != y ]

for 循环
  在介绍for循环之前,我们要学个非常有用的unix命令:shift。我们知道,对于位置变量或命令行参数,其个数必须是确定的,或者当Shell程序不知道其个数时,可以把所有参数一起赋值给变量$*。若用户要求Shell在不知道位置变量个数的情况下,还能逐个的把参数一一处理,也就是在$1后为$2,在$2后面为$3等。在 shift命令执行前变量$1的值在shift命令执行后就不可用了。

示例如下:

#测试shift命令(x_shift.sh)
until [ $# -eq 0 ]
do
echo "第一个参数为: $1 参数个数为: $#"
shift
done
执行以上程序x_shift.sh:
$./x_shift.sh 1 2 3 4

结果显示如下:

第一个参数为: 1 参数个数为: 3
第一个参数为: 2 参数个数为: 2
第一个参数为: 3 参数个数为: 1
第一个参数为: 4 参数个数为: 0

从上可知shift命令每执行一次,变量的个数($#)减一,而变量值提前一位,下面代码用until和shift命令计算所有命令行参数的和。

#shift上档命令的应用(x_shift2.sh)
if [ $# -eq 0 ]
then
echo "Usage:x_shift2.sh 参数"
exit 1
fi
sum=0
until [ $# -eq 0 ]
do
sum=`expr $sum + $1`
shift
done
echo "sum is: $sum"

执行上述程序:

$x_shift2.sh 10 20 15

其显示结果为:

45

  shift命令还有另外一个重要用途,Bsh定义了9个位置变量,从$1到$9,这并不意味着用户在命令行只能使用9个参数,借助shift命令可以访问多于9个的参数。

  Shift命令一次移动参数的个数由其所带的参数指定。例如当shell程序处理完前九个命令行参数后,可以使用shift 9命令把$10移到$1。

  在熟悉了shift命令后,我们一起看看,Bsh程序中非常有用的for循环语句,这种循环同上面说的while和until循环不同,for语句中的循环是否执行并不由某个条件的真和假来决定,决定for循环是否继续的条件是参数表中是否还有未处理的参数。

For语句的结构如下:

for variable in arg1 arg2 … argn
do
command
command
… …
done

下面是for循环的简单例子:

for LETTER in a b c d
do
echo $LETTER
done

程序执行结果如下:

a
b
c
d

在上面计算参数和的例子中,我们可以用for循环,实现如下:

#测试 for 程序(x_for.sh)

if [ $# -eq 0 ]
then
   echo "Usage:x_for.sh 参数… …"
   exit 1
fi
sum=0
for I in $*
do
   sum=`expr $sum + $I`
done
echo "sum is: $sum"

中断循环指令

  在程序循环语句中,我们有时候希望遇到某中情况时候结束本次循环执行下次循环或结束这个循环,这就涉及到两条语句:continue和break。continue命令可使程序忽略其后循环体中的其他指令,直接进行下次循环,而break命令则立刻结束循环,执行循环体后面的的语句。

#测试continue
I=1
while [ $I -lt 10 ]
do
  if [ $I -eq 3 ]
  then
    continue
  fi
  if [ $I -eq 7 ]
  then
    break
  fi
  echo "$I\c"
done

执行上面程序,结果如下:

12456789
与或结构

使用与/或结构有条件的执行命令

  Shell程序中可以使用多种不同的方法完成相同的功能,例如until和while语句就可以完成相同的功能,同样,除了if-then-else结构可以使命令有条件的执行外,$$和||操作符也能完成上述功能。在C语言中这两个操作符分别表示逻辑与和逻辑或操作。在Bourne Shell中,用&&连接两条命令的含义只有前面一条命令成功执行了,后面的命令才会执行。

  &&操作的形式为:

    command && command

  例如语句:

    rm $TEMPDIR/* && echo "Files successfully removed"

  只有rm命令成功执行以后,才会执行echo命令。若用if-then语句实现上述功能,形式为:

    if rm $TEMPDIR/*
    then
      echo "Files successfully removed"
    fi
  相反,用||连接两条命令的含义为只有第一条命令执行失败才执行第二条命令,例如:

    rm $TEMPDIR/* || echo "File were not removed"

  上面语句的等价形式为:

    if rm $TEMPDIR/*
    then
      :
    else
      echo "Files were not removed"
    fi
  这两种操作符可以联合使用,如在下面的命令行中,只有command1和command2执行成功后,command3才会执行:

    command1 && command2 && command3

  下面的命令行表示只有command1成功执行,command2不成功执行时,才会执行command3。

  &&和||操作符可以简化命令条件执行的格式,但一般只用于一条命令的条件执行。如果许多命令都使用这两个操作符,那么整个程序的可读性将变的很差,所以在多条命令的条件执行时,最好采用可读性好的if语句。

函数

  现在我们介绍Shell程序中的函数部分,基本上任何高级语言都支持函数这个东西,能让我们胜好多事情的东西,至少省的频繁的敲击相同的东西,好了come on
Shell程序中的函数

  函数又叫做子程序,可以在程序中的任何地方被调用,其格式如下:

  函数名字()
  {
    command
    ... ...
    command;
  }

  Shell程序的任何地方都可以用命令 "函数名字" 调用,使用函数的好处有两点,一点是使用函数可以把一个复杂的程序化为多个模块,易于管理,符合结构化程序的设计思想,另一个好处是代码的重用。

  Shell函数和Shel程序比较相似,它们的区别在于Shell程序在子Shell中运行,而Shell函数在当前Shell中运行。因此,在当前Shell中可以看到Shell函数对变量的修改。在任何Shell中都可以定义函数,包括交互式Shell。

  例如:

    $dir() {ls -l;}

    结果是我们在$后面打dir,其显示结果同ls -l的作用是相同的。该dir函数将一直保留到用户从系统退出,或执行了如下所示的unset命令:
    $unset dir
    下面的例子说明了函数还可以接受位置参数:

    $dir(){_
    >echo "permission    ln owner   group    file sz last access
    >ls -l $*;
    >}

    运行 dir a* 看产生什么结果

    参数a*传递到dir函数中并且代替了$*

    通常Shell程序将在子Shell中执行,该程序对变量的改变只在子Shell中有效而在当前Shell中无效。"."命令可以使Shell程序在当前Shell中执行。用户可以在当前Shell中定义函数和对变量赋值。通常用下面命令来重新初使化.profile对Shell环境的设置。
    $ . .profile
  由于看到这部分相对简单,我们还是顺便说说trap好了

使用trap命令进行例外处理

  用户编写程序在程序运行时可能会发生一些例外情况,比如执行该程序的用户按中断键或使用kill命令,或者控制终端突然与系统断开等。unix系统中的上述情况会使系统向进程发一个信号,通常情况下该信号使进程终止运行。有时侯用户希望进程在接到终止信号时进行一些特殊的操作。若进程在运行时产生一些临时文件,又因接受到的信号而终止。那么该进程产生的临时文件将保留下来。在bsh中,用户可以使用trap命令修改进程接收到终止信号时进行的默认操作。
  trap命令格式如下:

     trap command_string signals
多数系统中共有15种发给进程的信号,默认情况下大多数信号都会使程序终止。用户最好查阅自己系统的文挡,看看本系统内使用的信号种类。除了信号为9(真正的kill信号)不能使用trap命令外,其他信号所带来的操作都可以用trap命令进行指定。下面是trap命令中经常使用的几种信号:

    信号   功能
    
     1     挂起
     2    操作中断
     15    软终止(kill信号)

  若命令串中包含不只一条命令,必须使用引号将整个命令括起来,具体是单引号还是双引号,由用户是否需要变量替换决定。" "替换,' '不替换。

  使用下面trap命令可以使程序在接收到挂起、中断或kill信号时,首先把临时文件删除,然后退出:

    trap "rm $TEMPDIR/* $$;exit" 1 2 15

  在上面例子中,当Shell读取trap命令时,首先对$TEMPDIR和$$进行变量替换,替换之后的命令串将被保存在trap表中,若上例中trap命令使用单引号时,trap命令执行时候,不进行变量替换,而把命令串 rm $TEMPDIR/* $$;exit 放到trap表中,当检测到信号时,程序解释执行trap表中的命令串,此时进行变量替换。前面变量$TEMPDIR和$$的值为执行trap指令时候的值,后一种情况中变量的值为程序接收到信号时候的值,所以 "、'一定要区分仔细。

  下面命令的含义为用户按二次中断键后,程序才终止:

    trap 'trap 2' 2

  一般trap命令中的命令串中几乎都包含exit语句,上面rm的例子若无exit语句,接收到信号rm命令执行完后程序将挂起。但有时用户也需要程序在接到信号后挂起,例如当终端和系统断开后,用户发出挂起信号,并执行空命令,如下:

    trap : 1

  若用户想取消前trap指令设置的命令串,可以再执行trap命令,在命令中不指定命令串表示接收到信号后进行默认的操作,命令如下:
    trap 1

规范Shell

获取UNIX类型的选项:

  unix有一个优点就是标准UNIX命令在执行时都具有相同的命令行格式:

  command -options parameters

  如果在执行Shell程序也采用上述格式,Bourne Shell中提供了一条获取和处理命令行选项的语句,即getopts语句。该语句的格式为:

  getopts option_string variable

  其中option_string中包含一个有效的单字符选项。若getopts命令在命令行中发现了连字符,那么它将用连字符后面的字符同option_string相比较。若有匹配,则把变量variable的值设为该选项。若无匹配,则variable设为?。当getopts发现连字符后面没有字符,会返回一个非零的状态值。Shell程序中可以利用getopts的返回值建立一个循环。

  下面代码说明了date命令中怎么使用getopts命令处理各种选项,该程序除了完成unix的标准命令date的功能外,还增加了许多新的选项。
  #新date程序
  if [ $# -lt 1 ]
  then
    date
  else
    while getopts mdyDHMSTJjwahr OPTION
    do
      case $OPTION
      in
        m)date '+%m';;
        d)date '+%d';;
        y)date '+%y';;
        D)date '+%D';;
        H0date '+%H';;
        M)date '+%M';;
        S)date '+%S';;
        T)date '+%T';;
        j)date '+%j';;
        J)date '+%y%j';;
        w)date '+%w';;
        a)date '+%a';;
        h)date '+%h';;
        r)date '+%r';;
        \?)echo "无效的选项!$OPTION";;
      esac
    done
  fi

  有时侯选项中还带一个值,getopts命令同样也支持这一功能。这时需要在option_string中选项字母后加一个冒号。当getopts命令发现冒号后,会从命令行该选项后读取该值。若该值存在,那么将被存在一个特殊的变量OPTARG中。如果该值不存在,getopts命令将在OPTARG中存放一个问号,并且在标准错误输出上显示一条消息。

  下面的例子,实现拷贝一个文件,并给文件赋一个新的名字。-c选项指定程序拷贝的次数,-v选项要求显示新创建文件的文件名。

  #--拷贝程序

  COPIES=1
  VERBOSE=N
  while getopts vc:OPTION
  do
    case $OPTION
    in
      c)COPIES=$OPTARG;;
      v)VERBOSE=Y;;
      \?)echo "无效参数!"
        exit 1;;
    esac
  done
  if [ $OPTIND -gt $# ]
  then
    echo "No file name specified"
     exit 2
  fi
  shift 'expr $OPTIND - 1'
  FILE=$1
  COPY=0
  while [ $COPIES -gt $COPY ]
  do
    COPY='expr $COPY + 1'
    cp $FILE $ {FILE} $ {COPY}
    if [ VERBOSE = Y }
    then
      echo ${FILE} $ {COPY}
    fi
  done


规范Shell:

  我们知道环境变量PS1是提示符,看下面程序chdir:
  if [ ! -d "$!" ]
  then
    echo "$1 is not a directory"
    exit 1
  fi
  cd $1
  PS1="'pwd'>"
  export PS1

  我们执行:

    $chdir /usr/ice666

  结果提示符号变成/usr/ice666>了吗?没有,为什么?

  原因在于:chdir在子Shell中执行,变量PS1的修改在当前Shell中也不会起作用,若要chdir完成意想中的功能,必须在当前Shell中执行该命令。最好的方法就是把其改成一个函数并且在.profile文件中定义。但若要把函数放到单个文件中并在当前Shell中执行,则需要使用 . 命令,并将chdir重写成一个函数,把其中的exit改写成return。下面代码是 .ice_ps的内容:

  #--提示符
  chdir()
  {
  if [ !-d "$1" ]
  then
    echo " $1 is not a directory"
    return
  fi
  cd $1
  PS1="'pwd'>"
  export PS1;
  }

  然后我们在.profile文件中加入下面语句

  .ice_ps

  然后在切换目录的时候,我们用chdir命令,结果是什么呢,自己实验好了!  
调试Shell程序
1>调试shell程序

  用户刚编写完Shell程序中,不可避免的会有错误,这时我们可以利用Bsh中提供的跟踪选项,该选项会显示刚刚执行的命令及参数。用户可以通过set命令打开-x选项或在启动Shell使用-x选项将Shell设置成跟踪模式。例如有下面代码ice_tx:

  if [ $# -eq 0 ]
  then
    echo "usage:sumints integer list"
    exit 1
  fi
  sum=0
  until [ $# -eq 0 ]
  do
    sum='expr $sum + $1'
    shift
  done
  echo $sum

  我们用跟踪模式运行:

  $sh -x ice_tx 2 3 4
  结果显示:
  +[ 3 -eq 0 ]
  +sum=0
  +[ 3 -eq 0 ]
  +expr 0+2
  +sum=2
  +shift
  +[ 2 -eq 0 ]
  +expr 2+3
  +sum=5
  +shift
  +[ 1 -eq 0 ]
  +expr 5+4
  +sum=9
  +[ 0 -eq 0 ]
  +echo 9
  9

  从上面可以看出,跟踪模式下Shell显示执行的每一条命令以及该命令使用的变量替换后的参数值。一些控制字如if、then、until等没显示。
2>命令分组

  Shell中若干命令可以组成一个单元一起执行。为了标识一组命令,这些命令必须放到"()"或"{}"中。放在"()"中的命令将在子Shell中运行,而放在"{}"中的命令将在当前Shell中运行。子Shell中运行的命令不影响当前Shell的变量。当前Shell中运行的命令影响当前Shell的变量。

  $NUMBER=2
  $(A=2;B=2;NUMBER='expr $A+$B';echo $NUMBER)
  结果为:4
  $echo $NUMBER
  结果为:2
  如果把上面的()变成{},结果会是怎么样的呢?

3>使用Shell分层管理器shl

  UNIX是一个多道程序设计的操作系统,一些UNIX系统利用这一特性提供了Shell层次管理器shl。使用shl用户一次可以打开多个层次的Shell,其中活跃的Shell可以从终端上获得输入。但所有Shell的输出都可在终端上显示,除非显示被禁止。

  多个Shell中有一个为shl,当用户在某个Shell中工作时,可以通过使用特殊字符(一般为Ctrl+z)返回shl。为了同其他Shell区别,shl中提示符为">>>"。当用户工作在Shell层次管理器中时,可以创建、激活和删除Shell,下面是shl中使用的命令。

  create name    产生名为name的层次
  delete name    删除名为name的层次
  block name     禁止名为name的层次的输出
  unblock name    恢复名为name的层次的输出
  resume name    激活名为name的层次
  toggle       激活近来经常使用的层次
  name        激活名为name的层次

  layers [-l] name  对于表中的每个层次,显示其正在运行的进程的进程号,-l选项要求显示详细信息。

  help        显示shl命令的帮助信息
  quit        退出shl以及所有被激活的层次

总结

  在前面我们主要介绍了sh的变量、基本语法、程序设计等。如果掌握了这些内容,在学习其他UNIX下编程语言的时候,相信有一定的好处,我们说了,在大多数的UNIX中都提供Bourn Shell,而且很少有象sh这样强大的脚本编辑语言了,是系统管理员和程序员的一笔财富,并且不需要额外的软件环境,对文件等处理借助unix命令,实现起来比c实现还要简单。
_________________

 ╭══╮
╭╯∑∑║.oo
╰⊙═⊙╯  想和妳一起吹吹風
[ 不要嫌车破哦~:]
分享到:
评论

相关推荐

    Unix系列shell程序编写(上).txt

    Unix系列shell程序编写(上)

    UNIX和Shell程序设计权威教程pdf

    《UNIX和Shell程序设计权威教程》是一本深入探讨UNIX操作系统及其Shell编程的宝贵资源。这本书旨在帮助读者理解和掌握UNIX系统的基础以及如何利用Shell脚本来自动化日常任务,提升工作效率。UNIX是一种强大的多用户...

    UNIX和shell程序设计权威教程

    本书《UNIX和shell程序设计权威教程》深入浅出地介绍了这两个主题,为读者提供了全面而详细的学习资源。 UNIX系统是一种多用户、多任务的操作系统,它的设计哲学强调简洁和模块化,使得它成为开发高效软件的平台。...

    unix shell程序设计

    通过shell程序设计,用户能够将一系列的Unix命令组合成一个脚本,从而简化复杂的任务,提高工作效率。例如,脚本`ex1`包含三条命令:显示当前日期,显示当前工作目录,并将工作目录切换到其父目录。另一个例子`ex2`...

    精通 LINUX & UNIX Shell 程序设计.pdf 高清下载

    Linux与UNIX Shell程序设计涉及的知识面非常广泛,它主要包含操作系统的基础知识、Shell脚本的编写、调试、优化等技能。首先,Linux是一种类UNIX操作系统,以其开放源代码、强大的网络功能、稳定的性能以及广泛的...

    《unix和shell程序设计权威教程 》

    本书《Unix和Shell程序设计权威教程》深入浅出地介绍了这两个主题,为学习者提供了丰富的知识资源。 Unix操作系统是最早由Ken Thompson、Dennis Ritchie等人在贝尔实验室开发的一种多用户、多任务的操作系统。它以...

    Unix中的shell程序编写笔记

    在Unix操作系统中,Shell是一种命令行解释器,它充当了用户与系统内核之间的接口,允许用户通过输入命令来...这份“Unix系列shell程序编写.doc”文档将提供详细的指导和实例,帮助你成为一名熟练的Shell脚本开发者。

    shell编程教程.chm

    Unix系列shell程序编写(下) Unix系列shell程序编写(中) shell游戏:俄罗斯方块 shell游戏:五子棋 shell游戏:老虎机 shell游戏:贪吃蛇 shell游戏:扫雷 初学者入门教程:Shell编程概述(一) 初学者入门教程:...

    shell程序实验报告

    本次实验旨在使学习者掌握在Unix系统下的基本操作及Shell程序设计方法。通过实际编程任务加深对Shell脚本的理解,具体目标包括: 1. **熟悉Unix环境下的基本操作**:这包括文件管理、目录导航、文件权限设置等常用...

    Unix_shell.rar_Unix shell

    在"Unix系列shell程序编写.doc"中,你可能会学到以下内容: 1. **Shell基础**:了解不同类型的Shell,如Bash(Bourne-Again SHell)、C Shell、Korn Shell等,以及它们的特点和适用场景。 2. **Shell命令**:学习...

    unix shell脚本编程

    Unix Shell脚本编程是Unix操作系统中一种强大的自动化工具,它允许用户编写一系列命令,形成一个可执行的文本文件,称为Shell脚本。这种脚本语言的功能强大且灵活,类似于高级编程语言,但更加轻量级,特别适合进行...

    shell编写 shell编写

    而在Shell编写中,我们所说的"shell脚本"(Shell script)是一种使用Shell语言编写的程序,用于自动化一系列的系统任务。在Linux或Unix环境中,Bash Shell是最常用的一种Shell,因此我们通常所说的Shell编写指的是...

    unix和shell程序设计权威教程

    《Unix和Shell程序设计权威教程》是一本深入探讨Unix操作系统及其Shell编程的宝贵资源。这本书旨在帮助读者理解和掌握Unix环境下的高效工作方式,以及利用Shell脚本自动化日常任务。Unix系统以其稳定、强大和可扩展...

    Linux与UNIX Shell编程指南.pdf

    在Linux与UNIX操作系统下,进程是操作系统中执行程序的基本单元。Shell脚本可以对进程进行控制,包括进程创建、进程管理、进程通信等。作业控制是指Shell脚本中对进程的 Background执行和Foreground执行的控制。 8....

    shell程序编写.pdf

    ### Shell程序编写:掌握Unix/Linux的强大工具 #### Shell:用户与系统的桥梁 Shell是Unix/Linux操作系统中的用户界面,它提供了一个交互式的环境,允许用户通过命令行输入指令,执行各种操作。与DOS的`command`...

    linux作业:编写shell程序

    ### Linux作业:编写Shell程序详解 #### 一、实验背景与目标 本次实验的主要目标是通过使用UNIX/Linux下的系统调用(如`fork()`、`dup()`和`pipe()`等),开发一个具备基本Shell功能的C语言程序。该程序不仅需要...

    shell教程shell脚本编写方

    Shell 程序是一种文本文件,该文件中存放了一系列 Shell 可识别的 Unix 命令。 Shell 程序可以执行多种命令,包括 Shell 内部命令、Unix 系统命令、编译好的可执行文件甚至 Shell 传递的位置参数。 执行一个 Shell...

    Unix Oracle Shell Scripting

    - **脚本**:Unix Shell脚本是由一系列命令组成的文件,它们可以被shell解释并执行。脚本通常包含变量赋值、条件判断、循环结构等元素。 - **参数传递**:当调用脚本时,可以通过命令行传递参数,这些参数可以在...

    shell程序编写.doc

    本文档"shell程序编写.doc"详细介绍了Shell的基本概念、语法和程序设计,非常适合初学者和进阶者学习。以下是关于Shell编程的一些关键知识点: 1. **Shell是什么?** Shell是操作系统与用户交互的接口,它允许用户...

Global site tag (gtag.js) - Google Analytics