现在的位置: 首页 > 综合 > 正文

Shell编程基础

2014年11月12日 ⁄ 综合 ⁄ 共 8319字 ⁄ 字号 评论关闭
                      Linux 的 Shell 编程
     其实作为命令语言互动式地解释和执行用户输入的命令只是 Shell 功能的一个方面,Shell
还可以用来进行程序设计,它提供了定义变量和参数的手段以及丰富的程序控制结构。 使用
Shell 编程类似于 DOS 中的批处理文件,称为 Shell script,又叫 Shell 程序或 Shell 命令文件。
Shell 基本语法
  像高级程序设计语言一样, Shell 也提供说明和使用变量的功能。对 Shell 来讲,所有变
量的取值都是一个字串,Shell 程序采用$var 的形式来引用名为 var 的变量的值。
  Shell 有以下几种基本类型的变量。
  (1)Shell 定义的环境变量:
  Shell 在开始执行时就已经定义了一些和系统的工作环境有关的变量,用户还可以重新定
义这些变量,常用的 Shell 环境变量有:
  HOME 用于保存注册目录的完全路径名。
  PATH 用于保存用冒号分隔的目录路径名,Shell 将按 PATH 变量中给出的顺序搜索这些目
录,找到的第一个与命令名称一致的可执行文件将被执行。
  TERM 终端的类型。
  UID 当前用户的识别字,取值是由数位构成的字串。
  PWD 当前工作目录的绝对路径名,该变量的取值随 cd 命令的使用而变化。
  PS1 主提示符,在特权用户下,默认的主提示符是 #,在普通用户下,默认的主提示符是
$。
  PS2 在 Shell 接收用户输入命令的过程中,如果用户在输入行的末尾输入“ /”然后回车,
或者当用户按回车键时 Shell 判断出用户输入的命令没有结束时,就显示这个辅助提示符,提
示用户继续输入命令的其余部分,默认的辅助提示符是>。
  (2)用户定义的变量:
  用户可以按照下面的语法规则定义自己的变量:
  变量名=变量值
  要注意的一点是,在定义变量时,变量名前不应加符号 $,在引用变量的内容时则应在变
量名前加$;在给变量赋值时,等号两边一定不能留空格,若变量中本身就包含了空格,则整
个字串都要用双引号括起来。
     在编写 Shell 程序时,为了使变量名和命令名相区别,建议所有的变量名都用大写字母来
表示。
     有时我们想要在说明一个变量并对它设置为一个特定值后就不在改变它的值时,可以用
下面的命令来保证一个变量的只读性:
                                                                 1
  readonly 变量名
  在任何时候,创建的变量都只是当前 Shell 的局部变量,所以不能被 Shell 运行的其他命
令或 Shell 程序所利用,而 export 命令可以将一个局部变量提供给 Shell 执行的其他命令使
用,其格式为:
  export 变量名
  也可以在给变量赋值的同时使用 export 命令:
  export 变量名=变量值
  使用 export 说明的变量,在 Shell 以后运行的所有命令或程序中都可以访问到。
  (3)位置参数:
  位置参数是一种在调用 Shell 程序的命令行中按照各自的位置决定的变量,是在程序名之
后输入的参数。位置参数之间用空格分隔, Shell 取第一个位置参数替换程序文件中的 $1,第
二个替换$2,依次类推。$0 是一个特殊的变量,它的内容是当前这个 Shell 程序的文件名,所
以,$0 不是一个位置参数,在显示当前所有的位置参数时是不包括$0 的。
  (4)预定义变量:
  预定义变量和环境变量相类似,也是在 Shell 一开始时就定义了的变量。所不同的是,用
户只能根据 Shell 的定义来使用这些变量,而不能重定义它。所有预定义变量都是由 $符和另
一个符号组成的,常用的 Shell 预定义变量有:
  $# 位置参数的数量。
  $* 所有位置参数的内容。
  $? 命令执行后返回的状态。
  $$ 当前进程的进程号。
  $! 后台运行的最后一个进程号。
  $0 当前执行的进程名。
  其中,$?用于检查上一个命令执行是否正确。(在 Linux 中,命令退出状态为 0 表示该命
令正确执行,任何非 0 值表示命令出错。)
  $$变量最常见的用途是用做暂存文件的名字以保证暂存文件不会重复。
  (5)参数置换的变量:
  Shell 提供了参数置换功能以便用户可以根据不同的条件来给变量赋不同的值。参数置换
的变量有 4 种,这些变量通常与某一个位置参数相联系,根据指定的位置参数是否已经设置
类决定变量的取值,它们的语法和功能分别如下。
  a. 变量=${参数 -word}:如果设置了参数,则用参数的值置换变量的值,否则用 word 置
换。即这种变量的值等于某一个参数的值,如果该参数没有设置,则变量就等于 word 的值。
                                                     2
  b. 变量=${参数=word}:如果设置了参数,则用参数的值置换变量的值,否则把变量设置
成 word,然后再用 word 替换参数的值。注意,位置参数不能用于这种方式,因为在 Shell 程
序中不能为位置参数赋值。
   c. 变量 =${ 参数? word} :如果设置了参数,则用参数的值置换变量的值,否则就显示
word 并从 Shell 中退出,如果省略了 word,则显示标准信息。这种变量要求一定等于某一个
参数的值。如果该参数没有设置,就显示一个信息,然后退出,因此这种方式常用于出错指
示。
  d. 变量=${参数+word}:如果设置了参数,则用 word 置换变量,否则不进行置换。
  所有这 4 种形式中的“参数”既可以是位置参数,也可以是另一个变量,只是用位置参
数的情况比较多。
Shell 程序设计的流程控制
  和其他高级程序设计语言一样, Shell 提供了用来控制程序执行流程的命令,包括条件分
支和循环结构,用户可以用这些命令创建非常复杂的程序。
  与传统语言不同的是,Shell 用于指定条件值的不是布尔运算式,而是命令和字串。
  1.测试命令
  test 命令用于检查某个条件是否成立,它可以进行数值、字符和文件 3 个方面的测试,其
测试符和相应的功能分别如下。
  (1)数值测试:
  -eq 等于则为真。
  -ne 不等于则为真。
  -gt 大于则为真。
  -ge 大于等于则为真。
  -lt 小于则为真。
  -le 小于等于则为真。
  (2)字串测试:
  = 等于则为真。
  != 不相等则为真。
  -z 字串 字串长度伪则为真。
  -n 字串 字串长度不伪则为真。
  (3)文件测试:
  -e 文件名 如果文件存在则为真。
  -r 文件名 如果文件存在且可读则为真。
  -w 文件名 如果文件存在且可写则为真。
                                                   3
  -x 文件名 如果文件存在且可执行则为真。
  -s 文件名 如果文件存在且至少有一个字符则为真。
  -d 文件名 如果文件存在且为目录则为真。
  -f 文件名 如果文件存在且为普通文件则为真。
  -c 文件名 如果文件存在且为字符型特殊文件则为真。
  -b 文件名 如果文件存在且为块特殊文件则为真。
  另外,Linux 还提供了与(!)、或(-o)、非(-a)三个逻辑操作符,用于将测试条件
连接起来,其优先顺序为:!最高,-a 次之,-o 最低。
  同时,bash 也能完成简单的算术运算,格式如下:
  $[expression]
  例如:
  var1=2
  var2=$[var1*10+1]
  则 var2 的值为 21。
  2.if 条件语句
  Shell 程序中的条件分支是通过 if 条件语句来实现的,其一般格式为:
  if 条件命令串
  then
  条件为真时的命令串
  else
  条件为假时的命令串
  fi
  3.for 循环
  for 循环对一个变量的可能的值都执行一个命令序列。赋给变量的几个数值既可以在程序
内以数值列表的形式提供,也可以在程序以外以位置参数的形式提供。 for 循环的一般格式
为:
  for 变量名    [in 数值列表]
  do
  若干个命令行
  done
  变量名可以是用户选择的任何字串,如果变量名是 var ,则在 in 之后给出的数值将顺序
替换循环命令列表中的 $var。如果省略了 in,则变量 var 的取值将是位置参数。对变量的每一
个可能的赋值都将执行 do 和 done 之间的命令列表。
                                                 4
  4.while 和 until 循环
  while 和 until 命令都是用命令的返回状态值来控制循环的。While 循环的一般格式为:
  while
  若干个命令行 1
  do
  若干个命令行 2
  done
  只要 while 的“若干个命令行 1”中最后一个命令的返回状态为真, while 循环就继续执行
do...done 之间的“若干个命令行 2”。
  until 命令是另一种循环结构,它和 while 命令相似,其格式如下:
  until
   若干个命令行 1
  do
   若干个命令行 2
  done
  until 循环和 while 循环的区别在于: while 循环在条件为真时继续执行循环,而 until 则是
在条件为假时继续执行循环。
  Shell 还提供了 true 和 false 两条命令用于创建无限循环结构,它们的返回状态分别是总为
0 或总为非 0。
  5.case 条件选择
  if 条件语句用于在两个选项中选定一项,而 case 条件选择为用户提供了根据字串或变量
的值从多个选项中选择一项的方法,其格式如下:
  case string in
  exp-1)
  若干个命令行 1
  ;;
  exp-2)
   若干个命令行 2
  ;;
  ......
  *)
  其他命令行
  esac
                                                          5
  Shell 通过计算字串 string 的值,将其结果依次和运算式 exp-1, exp-2 等进行比较,直到找
到一个匹配的运算式为止。如果找到了匹配项,则执行它下面的命令直到遇到一对分号
(;;)为止。
  在 case 运算式中也可以使用 Shell 的通配符(“ *” 、“?”、“ [ ]” )。通常用 * 作为
case 命令的最后运算式以便在前面找不到任何相应的匹配项时执行“其他命令行”的命令。
  6.无条件控制语句 break 和 continue
  break 用于立即终止当前循环的执行,而 contiune 用于不执行循环中后面的语句而立即开
始下一个循环的执行。这两个语句只有放在 do 和 done 之间才有效。
  7.函数定义
  在 Shell 中还可以定义函数。函数实际上也是由若干条 Shell 命令组成的,因此它与 Shell
程序形式上是相似的,不同的是它不是一个单独的进程,而是 Shell 程序的一部分。函数定义
的基本格式为:
  functionname
  {
   若干命令行
  }
  调用函数的格式为:
  functionname param1 param2...
  Shell 函数可以完成某些例行的工作,而且还可以有自己的退出状态,因此函数也可以作
为 if, while 等控制结构的条件。
  在函数定义时不用带参数说明,但在调用函数时可以带有参数,此时 Shell 将把这些参数
分别赋予相应的位置参数$1, $2, ...及$*。
  8.命令分组
  在 Shell 中有两种命令分组的方法: ()和{}。前者当 Shell 执行()中的命令时将再创建一个
新的子进程,然后这个子进程去执行圆括弧中的命令。当用户在执行某个命令时不想让命令
运行时对状态集合(如位置参数、环境变量、当前工作目录等)的改变影响到下面语句的执
行时,就应该把这些命令放在圆括弧中,这样就能保证所有的改变只对子进程产生影响,而
父进程不受任何干扰。{}用于将顺序执行的命令的输出结果用于另一个命令的输入(管道方
式)。当我们要真正使用圆括弧和花括弧时(如计算运算式的优先顺序),则需要在其前面
加上转义符(/)以便让 Shell 知道它们不是用于命令执行的控制所用。
  9.信号
  trap 命令用于在 Shell 程序中捕捉信号,之后可以有 3 种反应方式:
  (1)执行一段程序来处理这一信号。
                                                          6
  (2)接受信号的默认操作。
  (3)忽视这一信号。
  trap 对上面 3 种方式提供了 3 种基本形式:
  第一种形式的 trap 命令在 Shell 接收到与 signal list 清单中数值相同的信号时,将执行双引
号中的命令串。
  trap 'commands' signal-list
  trap "commands" signal-list
  为了恢复信号的默认操作,使用第二种形式的 trap 命令:
  trap signal-list
  第三种形式的 trap 命令允许忽略信号:
  trap " " signal-list
  注意:
  ( 1 )对信号 11 (段违例)不能捕捉,因为 Shell 本身需要捕捉该信号去进行内存的转
储。
  (2 )在 trap 中可以定义对信号 0 的处理(实际上没有这个信号), Shell 程序在其终止
(如执行 exit 语句)时发出该信号。
  (3)在捕捉到 signal-list 中指定的信号并执行完相应的命令之后,如果这些命令没有将
Shell 程序终止的话,Shell 程序将继续执行收到信号时所执行的命令后面的命令,这样将很容
易导致 Shell 程序无法终止。
  另外,在 trap 语句中,单引号和双引号是不同的。当 Shell 程序第一次碰到 trap 语句时,
将把 commands 中的命令扫描一遍。此时若 commands 是用单引号括起来的话,那么 Shell 不
会对 commands 中的变量和命令进行替换,否则 commands 中的变量和命令将用当时具体的值
来替换。
运行 Shell 程序的方法
  用户可以用任何编辑程序来编写 Shell 程序。因为 Shell 程序是解释执行的,所以不需要
编 译 成 目 的 程 序 。 按 照 Shell 编 程 的 惯 例 , 以 bash 为 例 , 程 序 的 第 一 行 一 般
为“#!/bin/bash”,其中 # 表示该行是注释,叹号 !告诉 Shell 运行叹号之后的命令并用文
档的其余部分作为输入,也就是运行/bin/bash 并让/bin/bash 去执行 Shell 程序的内容。
  执行 Shell 程序的方法有 3 种。
  1.sh Shell 程序文件名
  这种方法的命令格式为:
  bash Shell 程序文件名
                                                                  7
  这实际上是调用一个新的 bash 命令解释程序,而把 Shell 程序文件名作为参数传递给它。
新启动的 Shell 将去读指定的文件,可执行文件中列出的命令,当所有的命令都执行完后结
束。该方法的优点是可以利用 Shell 调试功能。
  2.sh
  格式为:
  bash< Shell 程序名
  这种方式就是利用输入重定向,使 Shell 命令解释程序的输入取自指定的程序文件。
  3.用 chmod 命令使 Shell 程序成为可执行的
  一个文件能否运行取决于该文档的内容本身可执行且该文件具有执行权。对于 Shell 程
序,当用编辑器生成一个文件时,系统赋予的许可权都是 644(rw-r-r--),因此,当用户需要运
行这个文件时,只需要直接键入文件名即可。
  在这 3 种运行 Shell 程序的方法中,最好按下面的方式选择:当刚创建一个 Shell 程序,
对它的正确性还没有把握时,应当使用第一种方式进行调试。当一个 Shell 程序已经调试好
时,应使用第三种方式把它固定下来,以后只要键入相应的文件名即可,并可被另一个程序
所调用。
  4.bash 程序的调试
  在编程过程中难免会出错,有的时候,调试程序比编写程序花费的时间还要多, Shell 程
序同样如此。
  Shell 程序的调试主要是利用 bash 命令解释程序的选择项。调用 bash 的形式是:
  bash -选择项 Shell 程序文件名
  几个常用的选择项是:
  -e 如果一个命令失败就立即退出。
  -n 读入命令但是不执行它们。
  -u 置换时把未设置的变量看做出错。
  -v 当读入 Shell 输入行时把它们显示出来。
  -x 执行命令时把命令和它们的参数显示出来。
  上面的所有选项也可以在 Shell 程序内部用“ set - 选择项”的形式引用,而“ set + 选择
项”则将禁止该选择项起作用。如果只想对程序的某一部分使用某些选择项时,则可以将该
部分用上面两个语句包围起来。
  (1)未置变量退出和立即退出
  未置变量退出特性允许用户对所有变量进行检查,如果引用了一个未赋值的变量就终止
Shell 程序的执行。Shell 通常允许未置变量的使用,在这种情况下,变量的值为空。如果设置
                                                      8
了未置变量退出选择项,则一旦使用了未置变量就显示错误信息,并终止程序的运行。未置
变量退出选择项为-u。
  当 Shell 运行时,若遇到不存在或不可执行的命令、重定向失败或命令非正常结束等情况
时,如果未经重新定向,该出错信息会显示在终端屏幕上,而 Shell 程序仍将继续执行。要想
在错误发生时迫使 Shell 程序立即结束,可以使用-e 选项将 Shell 程序的执行立即终止。
  (2)Shell 程序的跟踪
  调试 Shell 程序的主要方法是利用 Shell 命令解释程序的-v 或-x 选项来跟踪程序的执行。-
v 选择项使 Shell 在执行程序的过程中,把它读入的每一个命令行都显示出来,而 -x 选择项使
Shell 在执行程序的过程中把它执行的每一个命令在行首用一个 +加上命令名显示出来。并把
每一个变量和该变量所取的值也显示出来。因此,它们的主要区别在于:在执行命令行之前
无-v,则显示出命令行的原始内容,而有-v 时则显示出经过替换后的命令行的内容。
  除了使用 Shell 的 -v 和 -x 选择项以外,还可以在 Shell 程序内部采取一些辅助调试的措
施。例如,可以在 Shell 程序的一些关键地方使用 echo 命令把必要的信息显示出来,它的作
用相当于 C 语言中的 printf 语句,这样就可以知道程序运行到什么地方及程序目前的状态。
bash 的内部命令
  bash 命令解释套装程序包含了一些内部命令。内部命令在目录列表时是看不见的,它们
由 Shell 本身提供。常用的内部命令有: echo, eval, exec, export, readonly, read, shift, wait 和点
(.)。下面简单介绍其命令格式和功能。
  1.echo
  命令格式:echo arg
  功能:在屏幕上显示出由 arg 指定的字串。
  2.eval
  命令格式:eval args
  功能:当 Shell 程序执行到 eval 语句时,Shell 读入参数 args,并将它们组合成一个新的命
令,然后执行。
  3.exec
  命令格式:exec 命令参数
  功能:当 Shell 执行到 exec 语句时,不会去创建新的子进程,而是转去执行指定的命令,
当指定的命令执行完时,该进程(也就是最初的 Shell)就终止了,所以 Shell 程序中 exec 后
面的语句将不再被执行。
  4.export
  命令格式:export 变量名 或:export 变量名=变量值
                                                                               9
  功能:Shell 可以用 export 把它的变量向下带入子 Shell,从而让子进程继承父进程中的环
境变量。但子 Shell 不能用 export 把它的变量向上带入父 Shell。
  注意:不带任何变量名的 export 语句将显示出当前所有的 export 变量。
  5.readonly
  命令格式:readonly 变量名
  功能:将一个用户定义的 Shell 变量标识为不可变。不带任何参数的 readonly 命令将显示
出所有只读的 Shell 变量。
  6.read
  命令格式:read 变量名表
  功能:从标准输入设备读入一行,分解成若干字,赋值给 Shell 程序内部定义的变量。
  7.shift 语句
  功能:shift 语句按如下方式重新命名所有的位置参数变量,即 $2 成为$1,$3 成为$2...在
程序中每使用一次 shift 语句,都使所有的位置参数依次向左移动一个位置,并使位置参数 $#
减 1,直到减到 0 为止。
  8.wait
  功能:使 Shell 等待在后台启动的所有子进程结束。wait 的返回值总是真。
  9.exit
  功能:退出 Shell 程序。在 exit 之后可有选择地指定一个数位作为返回状态。
  10.“.”(点)
  命令格式:. Shell 程序文件名
  功能:使 Shell 读入指定的 Shell 程序文件并依次执行文件中的所有语句。
                                                    10
 
【上篇】
【下篇】

抱歉!评论已关闭.