Gmail Calendar Documents Reader Web more »
Recently Visited Groups | Help | Sign in
Google Groups Home
Shell编程基础
There are currently too many topics in this group that display first. To make this topic appear first, remove this option from another topic.
There was an error processing your request. Please try again.
flag
  1 message - Expand all  -  Translate all to Translated (View all originals)
The group you are posting to is a Usenet group. Messages posted to this group will make your email address visible to anyone on the Internet.
Your reply message has not been sent.
Your post was successful
 
From:
To:
Cc:
Followup To:
Add Cc | Add Followup-to | Edit Subject
Subject:
Validation:
For verification purposes please type the characters you see in the picture below or the numbers you hear by clicking the accessibility icon. Listen and type the numbers you hear
 
upwinder  
View profile   Translate to Translated (View Original)
 More options Feb 22 2007, 6:43 pm
From: upwinder <upwin...@gmail.com>
Date: Fri, 23 Feb 2007 07:43:39 +0800
Local: Thurs, Feb 22 2007 6:43 pm
Subject: Shell编程基础
   #!/bin/sh

   ...

符号#!用来告诉系统执行该脚本的程序,本例使用/bin/sh。编辑结束并保存后,
如果要执行该脚本,必须先使其可执行:

   chmod +x filename

此后在该脚本所在目录下,输入 ./filename 即可执行该脚本。

0.1. 合理使用注释

________________________________________________________________________

shell 脚本中以# 开始的行表示注释,直到该行的结束。我们强烈建议你在脚本中
进行适当/合理的注释,这样一来,即便你在相当长时间内没有使用该脚本,也能
在短时间内就明白 它的作用和工作原理。此外,还有一个很重要的原因是,在注
释的帮助下,别人可以快速有效的分享你的脚本,并提出自己的意见和改进。

0.2. 变量赋值和引用

________________________________________________________________________

Shell编程中,使用变量无需事先声明,同时变量名的命名须遵循如下规则:

     1. 首个字符必须为字母(a-z,A-Z)
     2. 中间不能有空格,可以使用下滑线(_)
     3. 不能使用标点符号
     4. 不能使用bash里的关键字(可用help命令查看保留关键字)

需要给变量赋值时,可以这么写:

   变量名=值

要取用一个变量的值,只需在变量名前面加一个$:

   #!/bin/sh
   #对变量赋值:
   a="hello world"

   # 打印变量a的值:
   echo "A is:" $a

挑个自己喜欢的编辑器,输入上述内容,并保存为文件first,然后执行 chmod +x
first 使其可执行,最后输入 ./first 执行该脚本。其输出结果如下:

   A is: hello world

有时候变量名可能会和其它文字混淆,比如:

   num=2
   echo "this is the $numnd"

上述脚本并不会输出"this is the 2nd"而是"this is the ";这是由于shell会去
搜索变量numnd的值,而实际上这个变量此时并没有值。这时,我们可以用花括号
来告诉shell要打印的是num变量:

   num=2
   echo "this is the ${num}nd"

其输出结果为:this is the 2nd

Shell脚本中有许多变量是系统自动设定的,我们将在用到这些变量时再作说明。
除了只在脚本内有效的普通shell变量外,还有环境变量,即那些由export关键字
处理过的变量。本文不讨论环境变量,因为它们一般只在登录脚本中用到。

1. Shell里的命令

________________________________________________________________________

1.1. Unix 命令

________________________________________________________________________

在shell脚本中可以使用任意unix命令,不过实际上最为常用的一般都是那些文件
和文字操作相关的命令。下面介绍一些常用命令的语法和功能:

  echo "some text": 在屏幕上输出信息

  ls: 文件列表

  wc –l file wc -w file wc -c file: 分别计算文件的行数(line)、单词数(word)和字符数(character)

  cp sourcefile destfile: 文件拷贝

  mv oldname newname: 重命名文件或移动文件

  rm file: 删除文件

  grep 'pattern' file: 在文件内搜索字符串或和正则表达式匹配的字符串

  cut -b column file: 将指定范围内的文件内容输出到标准输出设备(屏幕)上。比如:输出每行第5至9个字符 cut -b5-9 file.txt,注意不要和cat命令混淆,这是两个完全不同的命令

  cat file.txt: 输出文件内容到标准输出设备(屏幕)上

  file somefile: 取得文件somefile的文件类型

  read var: 提示用户输入,并将输入内容赋值给变量var

  sort file.txt: 对file.txt文件所有行进行排序

  uniq: 只输出文件中内容不一致的行,如: sort file.txt | uniq

  expr: 进行数学运算,如要进行2+3的运算,命令为: expr 2 "+" 3

  find: 搜索文件,如根据文件名搜索:find . -name filename -print

  tee: 将数据输出到标准输出设备(屏幕) 和文件,比如:somecommand | tee outfile

  basename file: 返回不包含路径的文件名,如: basename /bin/tux 会返回 tux

  dirname file: 返回文件所在路径,如:dirname /bin/tux 会返回 /bin

  head file: 打印文本文件开头几行

  tail file : 打印文本文件末尾几行

  sed: 是一个基本的查找替换程序。可以从标准输入(如命令管道)读入文本,并将结果输出到标准输出(屏幕);该命令采用正则表达式进行搜索。不要和 shell中的通配符相混淆。比如将 ubuntu 替换为 Ubuntu :cat text.file | sed 's/ubuntu/Ubuntu/' > newtext.file

  awk: 用来提取文本文件中的字段。缺省的字段分割符是空格,可以使用 -F 指定其它分割符。cat file.txt | awk -F, '{print $1 "," $3 }',这里我们使用 , 作为字段分割符,同时打印第一和第三个字段。如果该文件内容为 Adam Bor, 34, IndiaKerry Miller, 22, USA,则上述命令的输出为:Adam Bor, IndiaKerry Miller, USA

1.2. 概念: 管道, 重定向和 backtick

________________________________________________________________________

尽管这些都不是系统命令,不过它们扮演着相当重要的角色。

      * 管道 (|) 将一个命令的输出作为另外一个命令的输入

   grep "hello" file.txt | wc -l

上述命令会在file.txt中搜索包含有”hello”的行并计算行数,这里grep命令的输
出成了wc命令的输入。

      * 重定向:将命令的结果输出到文件,而不是标准输出(屏幕)

   >  写入文件并覆盖旧文件
   >> 加到文件的尾部,保留旧文件内容
      * 反短斜线

反短斜线可以将一个命令的输出作为其它命令的命令行参数。

   find . -mtime -1 -type f -print

上述命令可以查找过去24小时(-mtime –2则表示过去48小时)内修改过的文件。
如果你想将上述命令查找到的所有文件打包,则可以使用如下脚本:

   #!/bin/sh

   # The ticks are backticks (`) not normal quotes ('):
   tar -zcvf lastmod.tar.gz `find . -mtime -1 -type f -print`

2. Shell里的流程控制

________________________________________________________________________

2.1. if 语句

________________________________________________________________________

"if"表达式如果条件为真,则执行then后的部分:

切换行号显示
   1    if ....; then
   2      ....
   3    elif ....; then
   4      ....
   5    else
   6      ....
   7    fi
大多数情况下,可以使用测试命令来对条件进行测试,比如可以比较字符串、判断
文件是否存在及是否可读等等……通常用" [ ] "来表示条件测试,注意这里的空格
很重要,要确保方括号前后的空格。

   [ -f "somefile" ] :判断是否是一个文件
   [ -x "/bin/ls" ] :判断/bin/ls是否存在并有可执行权限
   [ -n "$var" ] :判断$var变量是否有值
   [ "$a" = "$b" ] :判断$a和$b是否相等

执行man test可以查看所有测试表达式可以比较和判断的类型。下面是一个简单的
if语句:

切换行号显示
   1    #!/bin/sh
   2
   3    if [ "$SHELL" = "/bin/bash" ]; then
   4       echo "your login shell is the bash (bourne again shell)"
   5    else
   6       echo "your login shell is not bash but $SHELL"
   7    fi
变量$SHELL包含有登录shell的名称,我们拿它和/bin/bash进行比较以判断当前使
用的shell是否为bash。

2.2. && 和|| 操作符

________________________________________________________________________

熟悉C语言的朋友可能会喜欢下面的表达式:

   [ -f "/etc/shadow" ] && echo "This computer uses shadow passwords"

这 里的 && 就是一个快捷操作符,如果左边的表达式为真则执行右边的语句,你
也可以把它看作逻辑运算里的与操作。上述脚本表示如果/etc/shadow文件存在,
则 打印”This computer uses shadow passwords”。同样shell编程中还可以用或
操作(||),例如:

切换行号显示
   1    #!/bin/sh
   2
   3    mailfolder=/var/spool/mail/james
   4    [ -r "$mailfolder" ] || { echo "Can not read $mailfolder" ; exit 1; }
   5       echo "$mailfolder has mail from:"
   6       grep "^From " $mailfolder
该脚本首先判断mailfolder是否可读,如果可读则打印该文件中的"From" 一行。
如果不可读则或操作生效,打印错误信息后脚本退出。需要注意的是,这里我们必
须使用如下两个命令:

   -打印错误信息

   -退出程序

我们使用花括号以匿名函数的形式将两个命令放到一起作为一个命令使用;普通函
数稍后再作说明。即使不用与和或操作符,我们也可以用if表达式完成任何事情,
但是使用与或操作符会更便利很多。

2.3. case 语句

________________________________________________________________________

case表达式可以用来匹配一个给定的字符串,而不是数字(可别和C语言里的
switch...case混淆)。

   case ... in
      ...) do something here ;;
   esac

让我们看一个例子,file命令可以辨别出一个给定文件的文件类型,如:file
lf.gz,其输出结果为:

   lf.gz: gzip compressed data, deflated, original filename,
   last modified: Mon Aug 27 23:09:18 2001, os: Unix

我们利用这点写了一个名为smartzip的脚本,该脚本可以自动解压bzip2, gzip和
zip 类型的压缩文件:

切换行号显示
   1    #!/bin/sh
   2
   3    ftype=`file "$1"`
   4    case "$ftype" in
   5    "$1: Zip archive"*)
   6       unzip "$1" ;;
   7    "$1: gzip compressed"*)
   8       gunzip "$1" ;;
   9    "$1: bzip2 compressed"*)
  10       bunzip2 "$1" ;;
  11    *) error "File $1 can not be uncompressed with smartzip";;
  12    esac
ERROR: EOF in multi-line statement

你可能注意到上面使用了一个特殊变量$1,该变量包含有传递给该脚本的第一个参
数值。也就是说,当我们运行:

   smartzip articles.zip

$1 就是字符串 articles.zip。

2.4. select 语句

________________________________________________________________________

select表达式是bash的一种扩展应用,擅长于交互式场合。用户可以从一组不同的
值中进行选择:

切换行号显示
   1 select var in ... ; do
   2  break
   3 done
   4 .... now $var can be used ....
下面是一个简单的示例:

切换行号显示
   1 #!/bin/sh
   2
   3 echo "What is your favourite OS?"
   4 select var in "Linux" "Gnu Hurd" "Free BSD" "Other"; do
   5     break
   6 done
   7 echo "You have selected $var"
该脚本的运行结果如下:

What is your favourite OS?
1) Linux
2) Gnu Hurd
3) Free BSD
4) Other
#? 1
You have selected Linux

2.5. while/for 循环

________________________________________________________________________

在shell中,可以使用如下循环:

切换行号显示
   1 while ...; do
   2    ....
   3 done
只要测试表达式条件为真,则while循环将一直运行。关键字"break"用来跳出循
环,而关键字”continue”则可以跳过一个循环的余下部分,直接跳到下一次循环
中。

for循环会查看一个字符串列表(字符串用空格分隔),并将其赋给一个变量:

切换行号显示
   1 for var in ....; do
   2    ....
   3 done
下面的示例会把A B C分别打印到屏幕上:

切换行号显示
   1 #!/bin/sh
   2
   3 for var in A B C ; do
   4    echo "var is $var"
   5 done
下面是一个实用的脚本showrpm,其功能是打印一些RPM包的统计信息:

切换行号显示
   1 #!/bin/sh
   2
   3 # list a content summary of a number of RPM packages
   4 # USAGE: showrpm rpmfile1 rpmfile2 ...
   5 # EXAMPLE: showrpm /cdrom/RedHat/RPMS/*.rpm
   6 for rpmpackage in $*; do
   7    if [ -r "$rpmpackage" ];then
   8       echo "=============== $rpmpackage =============="
   9       rpm -qi -p $rpmpackage
  10    else
  11       echo "ERROR: cannot read file $rpmpackage"
  12    fi
  13 done
这 里出现了第二个特殊变量$*,该变量包含有输入的所有命令行参数值。如果你
运行showrpm openssh.rpm w3m.rpm webgrep.rpm,那么 $* 就包含有 3 个字符
串,即openssh.rpm, w3m.rpm和 webgrep.rpm。

3. Shell里的一些特殊符号

________________________________________________________________________

3.1. 引号

________________________________________________________________________

在向程序传递任何参数之前,程序会扩展通配符和变量。这里所谓的扩展是指程序
会把通配符(比如*)替换成适当的文件名,把变量替换成变量值。我们可以使用
引号来防止这种扩展,先来看一个例子,假设在当前目录下有两个jpg文件:
mail.jpg和tux.jpg。

切换行号显示
   1 #!/bin/sh
   2
   3 echo *.jpg
运行结果为:

   mail.jpg tux.jpg

引号(单引号和双引号)可以防止通配符*的扩展:

切换行号显示
   1 #!/bin/sh
   2
   3 echo "*.jpg"
   4 echo '*.jpg'
其运行结果为:

   *.jpg
   *.jpg

其中单引号更严格一些,它可以防止任何变量扩展;而双引号可以防止通配符扩展
但允许变量扩展:

切换行号显示
   1 #!/bin/sh
   2
   3 echo $SHELL
   4 echo "$SHELL"
   5 echo '$SHELL'
运行结果为:

切换行号显示
   1 /bin/bash
   2 /bin/bash
   3 $SHELL
此外还有一种防止这种扩展的方法,即使用转义字符——反斜杆:

   echo *.jpg
   echo $SHELL

输出结果为:

   *.jpg
   $SHELL

3.2. Here documents
当 要将几行文字传递给一个命令时,here documents一种不错的方法。对每个脚
本写一段帮助性的文字是很有用的,此时如果使用here documents就不必用echo函
数一行行输出。Here document以 << 开头,后面接上一个字符串,这个字符串还
必须出现在here document的末尾。下面是一个例子,在该例子中,我们对多个文
件进行重命名,并且使用here documents打印帮助:

切换行号显示
   1 #!/bin/sh
   2
   3 # we have less than 3 arguments. Print the help text:
   4 if [ $# -lt 3 ] ; then
   5 cat < ren -- renames a number of files using sed regular expressions
   6
   7 USAGE: ren 'regexp' 'replacement' files...
   8
   9 EXAMPLE: rename all *.HTM files in *.html:
  10    ren 'HTM$' 'html' *.HTM
  11
  12 HELP
  13    exit 0
  14 fi
  15
  16 OLD="$1"
  17 NEW="$2"
  18 # The shift command removes one argument from the list of
  19 # command line arguments.
  20 shift
  21 shift
  22 # $* contains now all the files:
  23 for file in $*; do
  24    if [ -f "$file" ] ; then
  25       newfile=`echo "$file" | sed "s/${OLD}/${NEW}/g"`
  26       if [ -f "$newfile" ]; then
  27        echo "ERROR: $newfile exists already"
  28       else
  29          echo "renaming $file to $newfile ..."
  30          mv "$file" "$newfile"
  31       fi
  32    fi
  33 done
ERROR: EOF in multi-line statement

这 个示例有点复杂,我们需要多花点时间来说明一番。第一个if表达式判断输入
命令行参数是否小于3个 (特殊变量$# 表示包含参数的个数) 。如果输入参数小于
3个,则将帮助文字传递给cat命令,然后由cat命令将其打印在屏幕上。打印帮助
文字后程序退出。如果输入参数等于或大于3个,我们 就将第一个参数赋值给变量
OLD,第二个参数赋值给变量NEW。下一步,我们使用shift命令将第一个和第二个
参数从参数列表中删除,这样原来的第三个 参数就成为参数列表$*的第一个参
数。然后我们开始循环,命令行参数列表被一个接一个地被赋值给变量$file。接
着我们判断该文件是否存在,如果存在则 通过sed命令搜索和替换来产生新的文件
名。然后将反短斜线内命令结果赋值给newfile。这样我们就达到了目的:得到了
旧文件名和新文件名。然后使用 mv命令进行重命名。

4. Shell里的函数

________________________________________________________________________

如果你写过比较复杂的脚本,就会发现可能在几个地方使用了相同的代码,这时如
果用上函数,会方便很多。函数的大致样子如下:

切换行号显示
   1 functionname()
   2 {
   3 # inside the body $1 is the first argument given to the function
   4 # $2 the second ...
   5 body
   6 }
你需要在每个脚本的开始对函数进行声明。

下面是一个名为xtitlebar的脚本,它可以改变终端窗口的名称。这里使用了一个
名为help的函数,该函数在脚本中使用了两次:

切换行号显示
   1 #!/bin/sh
   2 # vim: set sw=4 ts=4 et:
   3
   4 help()
   5 {
   6    cat < xtitlebar -- change the name of an xterm, gnome-terminal or kde konsole
   7
   8 USAGE: xtitlebar [-h] "string_for_titelbar"
   9
  10 OPTIONS: -h help text
  11
  12 EXAMPLE: xtitlebar "cvs"
  13
  14 HELP
  15    exit 0
  16 }
  17
  18 # in case of error or if -h is given we call the function help:
  19 [ -z "$1" ] && help
  20 [ "$1" = "-h" ] && help
  21
  22 # send the escape sequence to change the xterm titelbar:
  23 echo -e "33]0;$107"
  24 #
在脚本中提供帮助是一种很好的编程习惯,可以方便其他用户(和自己)使用和理
解脚本。

5. 命令行参数

________________________________________________________________________

我 们已经见过$* 和 $1, $2 ... $9 等特殊变量,这些特殊变量包含了用户从命
令行输入的参数。迄今为止,我们仅仅了解了一些简单的命令行语法(比如一些强
制性的参数和查看帮助的-h选项)。 但是在编写更复杂的程序时,您可能会发现
您需要更多的自定义的选项。通常的惯例是在所有可选的参数之前加一个减号,后
面再加上参数值 (比如文件名)。

有好多方法可以实现对输入参数的分析,但是下面的使用case表达式的例子无疑是
一个不错的方法。

切换行号显示
   1 #!/bin/sh
   2
   3 help()
   4 {
   5    cat < This is a generic command line parser demo.
   6    USAGE EXAMPLE: cmdparser -l hello -f -- -somefile1 somefile2
   7    HELP
   8    exit 0
   9 }
  10
  11 while [ -n "$1" ]; do
  12 case $1 in
  13    -h) help;shift 1;; # function help is called
  14    -f) opt_f=1;shift 1;; # variable opt_f is set
  15    -l) opt_l=$2;shift 2;; # -l takes an argument -> shift by 2
  16    --) shift;break;; # end of options
  17    -*) echo "error: no such option $1. -h for help";exit 1;;
  18    *) break;;
  19 esac
  20 done
  21
  22 echo "opt_f is $opt_f"
  23 echo "opt_l is $opt_l"
  24 echo "first arg is $1"
  25 echo "2nd arg is $2"
ERROR: EOF in multi-line statement

你可以这样运行该脚本:

   cmdparser -l hello -f -- -somefile1 somefile2

返回结果如下:

   opt_f is 1
   opt_l is hello
   first arg is -somefile1
   2nd arg is somefile2

这个脚本是如何工作的呢?脚本首先在所有输入命令行参数中进行循环,将输入参
数与case表达式进行比较,如果匹配则设置一个变量并且移除该参数。根据unix系
统的惯例,首先输入的应该是包含减号的参数。

6. Shell脚本示例

________________________________________________________________________

6.1. 一般编程步骤

________________________________________________________________________

现在我们来讨论编写一个脚本的一般步骤。任何优秀的脚本都应该具有帮助和输入
参数。写一个框架脚本(framework.sh),该脚本包含了大多数脚本需要的框架结
构,是一个非常不错的主意。这样一来,当我们开始编写新脚本时,可以先执行如
下命令:

   cp framework.sh myscript

然后再插入自己的函数。

让我们来看看如下两个示例。

6.2. 二进制到十进制的转换

________________________________________________________________________

脚本 b2d 将二进制数 (比如 1101) 转换为相应的十进制数。这也是一个用expr命
令进行数学运算的例子:

切换行号显示
   1 #!/bin/sh
   2 # vim: set sw=4 ts=4 et:
   3 help()
   4 {
   5    cat < b2h -- convert binary to decimal
   6
   7 USAGE: b2h [-h] binarynum
   8
   9 OPTIONS: -h help text
  10
  11 EXAMPLE: b2h 111010
  12 will return 58
  13 HELP
  14    exit 0
  15 }
  16
  17 error()
  18 {
  19    # print an error and exit
  20    echo "$1"
  21    exit 1
  22 }
  23
  24 lastchar()
  25 {
  26    # return the last character of a string in $rval
  27    if [ -z "$1" ]; then
  28       # empty string
  29       rval=""
  30       return
  31    fi
  32    # wc puts some space behind the output this is why we need sed:
  33    numofchar=`echo -n "$1" | wc -c | sed 's/ //g' `
  34    # now cut out the last char
  35    rval=`echo -n "$1" | cut -b $numofchar`
  36 }
  37
  38 chop()
  39 {
  40    # remove the last character in string and return it in $rval
  41    if [ -z "$1" ]; then
  42       # empty string
  43       rval=""
  44       return
  45    fi
  46    # wc puts some space behind the output this is why we need sed:
  47    numofchar=`echo -n "$1" | wc -c | sed 's/ //g' `
  48    if [ "$numofchar" = "1" ]; then
  49       # only one char in string
  50       rval=""
  51       return
  52    fi
  53    numofcharminus1=`expr $numofchar "-" 1`
  54    # now cut all but the last char:
  55    rval=`echo -n "$1" | cut -b 0-${numofcharminus1}`
  56 }
  57
  58 while [ -n "$1" ]; do
  59 case $1 in
  60    -h) help;shift 1;; # function help is called
  61    --) shift;break;; # end of options
  62    -*) error "error: no such option $1. -h for help";;
  63    *) break;;
  64 esac
  65 done
  66
  67 # The main program
  68 sum=0
  69 weight=1
  70 # one arg must be given:
  71 [ -z "$1" ] && help
  72 binnum="$1"
  73 binnumorig="$1"
  74
  75 while [ -n "$binnum" ]; do
  76    lastchar "$binnum"
  77    if [ "$rval" = "1" ]; then
  78       sum=`expr "$weight" "+" "$sum"`
  79    fi
  80    # remove the last position in $binnum
  81    chop "$binnum"
  82    binnum="$rval"
  83    weight=`expr "$weight" "*" 2`
  84 done
  85
  86 echo "binary $binnumorig is decimal $sum"
  87 #
ERROR: EOF in multi-line statement

该脚本使用的算法是利用十进制和二进制数权值 (1,2,4,8,16,..),比如二进
制"10"可以这样转换成十进制:

   0 * 1 + 1 * 2 = 2

为了得到单个的二进制数我们是用了lastchar 函数。该函数使用wc –c计算字符个
数,然后使用cut命令取出末尾一个字符。Chop函数的功能则是移除最后一个字
符。

6.3. 文件循环拷贝

________________________________________________________________________

你 可能有这样的需求并一直都这么做:将所有发出邮件保存到一个文件中。但是
过了几个月之后,这个文件可能会变得很大以至于该文件的访问速度变慢;下面的
脚本 rotatefile 可以解决这个问题。这个脚本可以重命名邮件保存文件(假设为
outmail)为outmail.1,而原来的outmail.1就变成了 outmail.2 等等...

切换行号显示
   1 #!/bin/sh
   2 # vim: set sw=4 ts=4 et:
   3
   4 ver="0.1"
   5 help()
   6 {
   7    cat < rotatefile -- rotate the file name
   8    USAGE: rotatefile [-h] filename
   9    OPTIONS: -h help text
  10    EXAMPLE: rotatefile out
  11
  12    This will e.g rename out.2 to out.3, out.1 to out.2, out to out.1[BR]
  13    and create an empty out-file
  14
  15    The max number is 10
  16
  17    version $ver
  18    HELP
  19
  20    exit 0
  21 }
  22
  23 error()
  24 {
  25    echo "$1"
  26    exit 1
  27 }
  28
  29 while [ -n "$1" ]; do
  30    case $1 in
  31       -h) help;shift 1;;
  32       --) break;;
  33       -*) echo "error: no such option $1. -h for help";exit 1;;
  34       *) break;;
  35    esac
  36 done
  37
  38 # input check:
  39 if [ -z "$1" ] ; then
  40    error "ERROR: you must specify a file, use -h for help"
  41 fi
  42
  43 filen="$1"
  44 # rename any .1 , .2 etc file:
  45 for n in 9 8 7 6 5 4 3 2 1; do
  46    if [ -f "$filen.$n" ]; then
  47       p=`expr $n + 1`
  48       echo "mv $filen.$n $filen.$p"
  49       mv $filen.$n $filen.$p
  50    fi
  51 done
  52
  53 # rename the original file:
  54 if [ -f "$filen" ]; then
  55    echo "mv $filen $filen.1"
  56    mv $filen $filen.1
  57 fi
  58
  59 echo touch $filen
  60 touch $filen
ERROR: EOF in multi-line statement

这 个脚本是如何工作的呢?在检测到用户提供了一个文件名之后,首先进行一个9
到1的循环;文件名.9重命名为文件名.10,文件名.8重命名为文件名. 9……等等。
循环结束之后,把原始文件命名为文件名.1,同时创建一个和原始文件同名的空文
件(touch $filen)。

7. 脚本调试

________________________________________________________________________

最简单的调试方法当然是使用echo命令。你可以在任何怀疑出错的地方用echo打印
变量值,这也是大部分shell程序员花费80%的时间用于调试的原因。Shell脚本的
好处在于无需重新编译,而插入一个echo命令也不需要多少时间。

shell也有一个真正的调试模式,如果脚本"strangescript"出错,可以使用如下命
令进行调试:

   sh -x strangescript

上述命令会执行该脚本,同时显示所有变量的值。

shell还有一个不执行脚本只检查语法的模式,命令如下:

   sh -n your_script

这个命令会返回所有语法错误。

我们希望你现在已经可以开始编写自己的shell脚本了,尽情享受这份乐趣吧!


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
End of messages
« Back to Discussions « Newer topic     Older topic »

Create a group - Google Groups - Google Home - Terms of Service - Privacy Policy
©2009 Google