<!-- /* Font Definitions */ @font-face {font-family:"MS 明朝"; panose-1:2 2 6 9 4 2 5 8 3 4; mso-font-alt:"MS Mincho"; mso-font-charset:128; mso-generic-font-family:roman; mso-font-pitch:fixed; mso-font-signature:-1610612033 1757936891 16 0 131231 0;} @font-face {font-family:SimSun; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-alt:宋体; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} @font-face {font-family:Century; panose-1:2 4 6 4 5 5 5 2 3 4; mso-font-charset:0; mso-generic-font-family:roman; mso-font-pitch:variable; mso-font-signature:647 0 0 0 159 0;} @font-face {font-family:"MS Pゴシック"; panose-1:2 11 6 0 7 2 5 8 2 4; mso-font-charset:128; mso-generic-font-family:modern; mso-font-pitch:variable; mso-font-signature:-1610612033 1757936891 16 0 131231 0;} @font-face {font-family:"/@SimSun"; panose-1:2 1 6 0 3 1 1 1 1 1; mso-font-charset:134; mso-generic-font-family:auto; mso-font-pitch:variable; mso-font-signature:3 135135232 16 0 262145 0;} @font-face {font-family:"/@MS 明朝"; panose-1:2 2 6 9 4 2 5 8 3 4; mso-font-charset:128; mso-generic-font-family:roman; mso-font-pitch:fixed; mso-font-signature:-1610612033 1757936891 16 0 131231 0;} @font-face {font-family:"/@MS Pゴシック"; panose-1:2 11 6 0 7 2 5 8 2 4; mso-font-charset:128; mso-generic-font-family:modern; mso-font-pitch:variable; mso-font-signature:-1610612033 1757936891 16 0 131231 0;} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {mso-style-parent:""; margin:0mm; margin-bottom:.0001pt; text-align:justify; text-justify:inter-ideograph; mso-pagination:none; font-size:10.5pt; mso-bidi-font-size:12.0pt; font-family:Century; mso-fareast-font-family:"MS 明朝"; mso-bidi-font-family:"Times New Roman"; mso-font-kerning:1.0pt;} a:link, span.MsoHyperlink {color:blue; text-decoration:underline; text-underline:single;} a:visited, span.MsoHyperlinkFollowed {color:purple; text-decoration:underline; text-underline:single;} p {mso-margin-top-alt:auto; margin-right:0mm; mso-margin-bottom-alt:auto; margin-left:0mm; mso-pagination:widow-orphan; font-size:12.0pt; font-family:"MS Pゴシック"; mso-bidi-font-family:"MS Pゴシック";} /* Page Definitions */ @page {mso-page-border-surround-header:no; mso-page-border-surround-footer:no;} @page Section1 {size:595.3pt 841.9pt; margin:99.25pt 30.0mm 30.0mm 30.0mm; mso-header-margin:42.55pt; mso-footer-margin:49.6pt; mso-paper-source:0; layout-grid:18.0pt;} div.Section1 {page:Section1;} -->
Linux 的 shell 编 程
http://tech.sina.com.cn/c/1338.html
Shell 本身是一个用 C 语 言 编 写的程序,它是用 户 使用 Linux 的 桥 梁。 Shell 既是一 种 命令 语 言,又是一 种 程序 设计语 言。作 为 命令 语 言,它交互式地解 释 和 执 行用 户输 入的命令;作 为 程序 设计语 言,它定 义 了各 种变 量和参 数,并提供了 许 多在高 级语 言中才具有的控制 结 构,包括循 环 和分支。它 虽 然不是 Linux 系 统 核心的一部分,但它 调 用了系 统 核心的大部分功能来 执 行程序、建 立文件并以并行的方式 协调 各个程序的运行。因此, 对 于用 户 来 说 , shell 是最重要的 实 用程序,深入了解和熟 练 掌握 shell 的特性极其使用方法,是用好 Linux 系 统 的 关键 。可以 说 , shell 使用的熟 练 程度反映了用 户对 Linux 使用的熟 练 程度。
一、什 么 是 shell
当一个用 户 登 录 Linux 系 统 之后,系 统 初始化程序 init 就 为每 一个用 户 运行一个称 为 shell( 外壳 ) 的程序。那 么 , shell 是什 么 呢? 确切一点 说 , shell 就是一个命令行解 释 器,它 为 用 户 提供了一个向 Linux 内核 发 送 请 求以便运行程序的界面系 统级 程序,用 户 可以用 shell 来启 动 、 挂起、停止甚至是 编 写一些程序。
当用 户 使用 Linux 时 是通 过 命令来完成所需工作的。一个命令就是用 户 和 shell 之 间对话 的一个基本 单 位,它是由多个字符 组 成并以 换 行 结 束的 字符串。 shell 解 释 用 户输 入的命令,就象 DOS 里的 command.com 所做的一 样 ,所不同的是,在 DOS 中, command.com 只有一个,而 在 Linux 下比 较 流行的 shell 有好几个, 每 个 shell 都各有千秋。一般的 Linux 系 统 都将 bash 作 为 默 认 的 shell 。
二、几 种 流行的 shell
目前流行的 shell 有 ash 、 bash 、 ksh 、 csh 、 zsh 等,你可以用下面的命令来 查 看你自己的 shell 类 型:
#echo $SHELL
$SHELL 是一个 环 境 变 量,它 记录 用 户 所使用的 shell 类 型。你可以用命令:
#shell-name
来 转换 到 别 的 shell , 这 里 shell-name 是你想要 尝试 使用的 shell 的名称,如 ash 等。 这 个命令 为 用 户 又启 动 了一个 shell , 这 个 shell 在最初登 录 的那个 shell 之后,称 为 下 级 的 shell 或子 shell 。使用命令:
$exit
可以退出 这 个子 shell 。
使用不同的 shell 的原因在于它 们 各自都有自己的特点,下面作一个 简单 的介 绍 :
1.ash
ash shell 是由 Kenneth Almquist 编 写的, Linux 中占用系 统资 源最少的一个小 shell ,它只包含 24 个内部命令,因而使用起来很不方便。
2.bash
bash 是 Linux 系 统 默 认 使用的 shell ,它由 Brian Fox 和 Chet Ramey 共同完成,是 Bourne Again Shell 的 缩 写,内部命令一共有 40 个。 Linux 使用它作 为 默 认 的 shell 是因 为 它有 诸 如以下的特色:
(1) 可以使用 类 似 DOS 下面的 doskey 的功能,用方向 键查阅 和快速 输 入并修改命令。
(2) 自 动 通 过查 找匹配的方式 给 出以某字符串 开头 的命令。
(3) 包含了自身的帮助功能,你只要在提示符下面 键 入 help 就可以得到相 关 的帮助。
3.ksh
ksh 是 Korn shell 的 缩 写,由 Eric Gisin 编 写,共有 42 条内部命令。 该 shell 最大的 优 点是几乎和商 业发 行版的 ksh 完全兼容, 这样 就可以在不用花 钱购买 商 业 版本的情况下 尝试 商 业 版本的性能了。
4.csh
csh 是Linux 比较 大的内核,它由以William Joy 为 代表的共计 47 位作者编 成,共有52 个内部命令。该 shell 其实 是指向/bin/tcsh 这样 的一个shell ,也就是说 ,csh 其实 就是tcsh 。
5.zch
zch 是Linux 最大的shell 之一,由Paul Falstad 完成,共有84 个内部命令。如果只是一般的用途,是没有必要安装这样 的shell 的。
3. shell 程序 设计 ( 基 础 部分 )
其 实 作 为 命令 语 言交互式地解 释 和 执 行用 户输 入的命令只是 shell 功能的一个方面, shell 还 可以用来 进 行程序 设计 ,它提供了定 义变 量和参数 的手段以及丰富的程序控制 结 构。使用 shell 编 程 类 似于 DOS 中的批 处 理文件,称 为 shell script ,又叫 shell 程序或 shell 命令文件。
1.shell 基本 语 法
shell 的基本 语 法主要就是如何 输 入命令运行程序以及如何在程序之 间 通 过 shell 的一些参数提供便利手段来 进 行通 讯 。
(1) 输 入 输 出重定向
在 Linux 中, 每 一个 进 程都有三个特殊的文件描述指 针 : 标 准 输 入 (standard input ,文件描述指 针为 0) 、 标 准 输 出 (standard output ,文件描述指 针为 1) 、 标 准 错误输 出 (standard error ,文件描述指 针为 2) 。 这 三个特殊的文件描述指 针 使 进 程在一般情况下接收 标 准 输 入 终 端的 输 入,同 时 由 标 准 终 端来 显 示 输 出, Linux 同 时 也向使 用者提供可以使用普通的文件或管道来取代 这 些 标 准 输 入 输 出 设备 。在 shell 中,使用者可以利用 “>” 和 “<” 来 进 行 输 入 输 出重定向。如:
command>file :将命令的 输 出 结 果重定向到一个文件。
command>&file :将命令的 标 准 错误输 出一起重定向到一个文件。
command>>file :将 标 准 输 出的 结 果追加到文件中。
command>>&file :将 标 准 输 出和 标 准 错误输 出的 结 构都追加到文件中。
command
(2) 管道 pipe
pipe 同 样 可以在 标 准 输 入 输 出和 标 准 错误输 出 间 做代替工作, 这样 一来,可以将某一个程序的 输 出送到另一个程序的 输 入,其 语 法如下:
command1| command2[| command3...]
也可以 连 同 标 准 错误输 出一起送入管道:
command1| &command2[|& command3...]
(3) 前台和后台
在 shell 下面,一个新 产 生的 进 程可以通 过 用命令后面的符号 “ ; ” 和 “&” 来分 别 以前台和后台的方式来 执 行, 语 法如下:
command
产 生一个前台的 进 程,下一个命令 须 等 该 命令运行 结 束后才能 输 入。
command &
产 生一个后台的 进 程,此 进 程在后台运行的同 时 ,可以 输 入其他的命令。
2 。 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 程序 时 , 为 了使 变 量名和命令名相区 别 ,建 议 所有的 变 量名都用大写字母来表示。
有 时 我 们 想要在 说 明一个 变 量并 对 它 设 定 为 一个特定 值 后就不在改 变 它的 值 , 这 可以用下面的命令来保 证 一个 变 量的只 读 性:
readly 变 量名
在任何 时 候,建立的 变 量都只是当前 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 提供了参数置 换 能力以便用 户 可以根据不同的条件来 给变 量 赋 不同的 值 。参数置 换 的 变 量有四 种 , 这 些 变 量通常与某一个位置参数相 联 系,根据指定的位置参数是否已 经设 置 类 决定 变 量的取 值 ,它 们 的 语 法和功能分 别 如下。
a. 变 量 =${ 参数 -word} :如果 设 置了参数, 则 用参数的 值 置 换变 量的 值 ,否 则 用 word 置 换 。即 这种变 量的 值 等于某一个参数的 值 ,如果 该 参数没有 设 置, 则变 量就等于 word 的 值 。
b. 变 量 =${ 参数 =word} :如果 设 置了参数, 则 用参数的 值 置 换变 量的 值 ,否 则 把 变 量 设 置成 word 然后再用 word 替 换 参数的 值 。注意,位置参数不能用于 这种 方式,因 为 在 shell 程序中不能 为 位置参数 赋值 。
c. 变 量 =${ 参数? word} :如果 设 置了参数, 则 用参数的 值 置 换变 量的 值 ,否 则 就 显 示 word 并从 shell 中退出,如果省略了 word , 则显 示 标 准信 息。 这种变 量要求一定等于某一个参数的 值 ,如果 该 参数没有 设 置,就 显 示一个信息,然后退出,因此 这种 方式常用于出 错 指示。
d. 变 量 =${ 参数 +word} :如果 设 置了参数, 则 用 word 置 换变 量,否 则 不 进 行置 换 。
所有 这 四 种 形式中的 “ 参数 ” 既可以是位置参数,也可以是另一个 变 量,只是用位置参数的情况比 较 多。
接下来以 bash 为 例向大家介 绍 shell 程序 设计 的高 级 部分: shell 编 程的流程控制、 调试 方法及 shell 程序的运行方法, 顺 便也向大家介 绍 一下 bash 的内部命令。
四、 shell 程序 设计 的流程控制
和其他高 级 程序 设计语 言一 样 , shell 提供了用来控制程序 执 行流程的命令,包括条件分支和循 环结 构,用 户 可以用 这 些命令建立非常 复杂 的程序。
与 传统 的 语 言不同的是, shell 用于指定条件 值 的不是布 尔 表达式而是命令和字符串。
1.test 测试 命令
test 命令用于 检查 某个条件是否成立,它可以 进 行数 值 、字符和文件三个方面的 测试 ,其 测试 符和相 应 的功能分 别 如下:
(1) 数 值测试 :
-eq :等于 则为 真
-ne :不等于 则为 真
-gt :大于 则为 真
-ge :大于等于 则为 真
-lt :小于 则为 真
-le :小于等于 则为 真
(2) 字符串 测试 :
= :等于 则为 真
!= :不相等 则为 真
-z 字符串:字符串 长 度 伪则为 真
-n 字符串:字符串 长 度不 伪则为 真
(3) 文件 测试 :
-e 文件名:如果文件存在 则为 真
-r 文件名:如果文件存在且可 读则为 真
-w 文件名:如果文件存在且可写 则为 真
-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.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
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 程序中捕捉到信号,之后可以有三 种 反 应 方式:
(1) 执 行一段程序来 处 理 这 一信号
(2) 接受信号的默 认 操作
(3) 忽 视这 一信号
trap 对 上面三 种 方式提供了三 种 基本形式:
第一 种 形式的 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 程序的方法有三 种 :
(1)sh shell 程序文件名
这种 方法的命令格式 为 :
bash shell 程序文件名
这实际 上是 调 用一个新的 bash 命令解 释 程序,而把 shell 程序文件名作 为 参数 传递给 它。新启 动 的 shell 将去 读 指定的文件, 执 行文件中列出的命令,当所有的命令都 执 行完 结 束。 该 方法的 优 点是可以利用 shell 调试 功能。
(2)sh
格式 为 :
bash
这种 方式就是利用 输 入重定向,使 shell 命令解 释 程序的 输 入取自指定的程序文件。
(3) 用chmod 命令使shell 程序成为 可执 行的
一个文件能否运行取决于 该 文件的内容本身可 执 行且 该 文件具有 执 行 权 。 对 于 shell 程序,当用 编辑 器生成一个文件 时 ,系 统赋 予的 许 可 权 限都是 644(rw-r-r--) ,因此,当用 户 需要运行 这 个文件 时 ,只需要直接 键 入文件名即可。
在 这 三 种 运行 shell 程序的方法中,最好按下面的方式 选择 :当 刚 建立一个 shell 程序, 对 它的正确性 还 没有把握 时 , 应 当使用第一 种 方式 进 行 调试 。当一个 shell 程序已 经调试 好 时 , 应 使用第三 种 方式把它固定下来,以后只要 键 入相 应 的文件名即可,并可被另一个程序所 调 用。
六、 bash 程序的 调试
在 编 程 过 程中 难 免会出 错 ,有的 时 候, 调试 程序比 编 写程序花 费 的 时间还 要多, shell 程序同 样 如此。
shell 程序的 调试 主要是利用 bash 命令解 释 程序的 选择项 。 调 用 bash 的形式是:
bash - 选择项 shell 程序文件名
几个常用的 选择项 是:
-e :如果一个命令失 败 就立即退出
-n : 读 入命令但是不 执 行它 们
-u :置 换时 把未 设 置的 变 量看作出 错
-v :当 读 入 shell 输 入行 时 把它 们显 示出来
-x : 执 行命令 时 把命令和它 们 的参数 显 示出来
上面的所有 选项 也可以在 shell 程序内部用 “set - 选择项 ” 的形式引用,而 “set + 选择项 ” 则 将禁止 该选择项 起作用。如果只想 对 程序的某一部分使用某些 选择项时 , 则 可以将 该 部分用上面两个 语 句包 围 起来。
1. 未置 变 量退出和立即退出
未置 变 量退出特性允 许 用 户对 所有 变 量 进 行 检查 ,如果引用了一个未 赋值 的 变 量就 终 止 shell 程序 的 执 行。 shell 通常允 许 未置 变 量的使用,在 这种 情况下, 变 量的 值为 空。如果 设 置了未置 变 量退出 选择项 , 则 一旦使用了未置 变 量就 显 示 错误 信息,并 终 止程 序的运行。未置 变 量退出 选择项为 “-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 变 量名 = 变 量 值
功能: 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 语 句,都使所有的位置参数依次向左移 动 一个位置,并使位置参数 “$#” 减一,直到减到 0 。
8.wait
功能:是 shell 等待在后台启 动 的所有子 进 程 结 束。 Wait 的返回值总 是真。
9.exit
功能:退出shell 程序。在 exit 之后可有 选择 地指定一个数字作 为 返回状 态 。
10.“.”( 点 )
命令格式: . Shell 程序文件名
功能:使shell 读 入指定的shell 程序文件并依次执 行文件中的所有语 句。