Shell编程从入门到精通-第03章
Shell 编程的基本元素
编程语言变量类型:变量对于编程语言来说很重要,编程语言使用变量来存储数据,执行运输。
静态类型语言:一种在编译期间就确定数据类型的语言。大多数是通过在使用任一变量之前声明其数据类型来保证这一点,例如 JAVA 和 C。
动态类型语言:一种在运行期间才去确定数据类型的语言。它确定一个变量的类型是在第一次给变量赋值的时候,例如 VBScript 和 Pthyhon。
强类型语言:一种总是强制类型定义的语言,当有一个整数时,不进行明确转换,不能把它当做一个字符串,例如 JAVA 和 Python。
弱类型语言:一种类型可以被忽略的语言,整数变量可以看做字符串,例如 VBScript 和 Shell。



shell 中的三种变量,用户变量在编程过程中使用最多,位置变量在对参数判断和命令返回值判断时会使用,环境变量主要是在程序运行的时候需要设置。
用户变量:用户在 shell 编程过程中定义的变量,分为局部变量和全局变量。默认情况下,用户定义的变量都是全局变量,使用 local 限定词定义的才是局部变量。变量定义的语法为 varname=value。等号两边不能有空格,而且变量值多余一个单词的情况下,需要将值用引号括起来。在命令中引用变量值时,需要在变量名前加上 $。
unset varname 可以删除变量,但 shell 在遇到未定义变量时返回错误,因此在正常情况下并不这样使用。
大括号操作符可以使用 shell 字符串操作的更多高级功能,即字符串处理运算符。它可以完成:确保变量存在且有值;设置变量的默认值;捕获未设置变量而导致的错误;删除匹配模式的变量的值部分内容。

上表中每个冒号都是可选的,如果省略冒号,则将每个定义中的“存在且非 null”改为“存在”,即变量运算符只判定变量是否存在。



上图中的变量替换,使用了两种方法,将 PATH 变量中的冒号都替换成了换行符。

再举一个例子,通过模式匹配删除等号(包括等号)之后的所有字符,输出部分就是变量名,删除等号(包括等号)之前的所有字符,输出部分就为变量值。

除了通过赋值语句与通过用户将变量作为命令行参数给出获取变量值之外,另外一种方法为命令替换。它允许使用命令的标准输出,就像一个变量值一样,语法为 `command`,这里 ` 为反引号,它将命令的输出作为表达式值。
位置变量:也称为系统变量、位置参数,是 shell 脚本运行时传递给脚本的参数,同时也表示在 shll 函数内部的函数参数。它们的名字是以数字命名 $0~$9,如果超过这个范围需要用括号括起来,即 ${10}。




shell 中内置了一个 shift 命令,它可以“截去”参数列表中最左端的一个,执行了 shift 后,$1 的值将会丢失,而 $2 的值将会赋给 $1,以此类推。$# 输出结果也会减一。shift 命令默认为 shift 1,即截去一个参数。


环境变量:影响当前 shell 进程运行情况的变量。
shell 执行命令的顺序:交互 shell 在获得用户输入时,并不是直接在 PATH 路径中查找,而是按照固定顺序依次查找命令位置。搜索顺序为别名(alias)、关键字(if、for)、函数、内置命令(cd、pwd)、外部命令(脚本或可执行程序,到这里才在 PATH 路径中查找)。
使用函数需要遵循以下的规则:先定义,后使用;允许以给位置参数赋值的方式向函数传递参数,函数体内部可以使用 local 限定词创建局部变量;在函数中使用 exit 命令将退出脚本,使用 return 命令退回到原本调用函数的地方,且 return 命令返回最后一条命令的退出状态;内置命令 export -f 可以将函数导出到子 shell 中;可以使用 source 或 dot 命令将保存在其他文件中的函数装入当前脚本;函数可以进行无限制的递归调用;可以使用 declare -f(-F) 找到登录会话中定义的函数。

函数定义分为上图中的两种形式,二者没有本质上的区别。unset -f funcname 可以删除定义的函数,-f 提示 unset 命令删除的是函数。




if/else 语句是 shell 内置的最简单的流程控制语句,用于判断当某条件成立时,则执行某些命令,常用于选项不多的情况。

在最简形式(没有 elif 和 else)中,只有当 condition 为真时,才执行 statements 语句;elif 可以有任意多个,它可以选择更多的条件,提供更多的选择,else 语句则当所有的 if 和 elif 的 condition 都为假时才执行。
命令(函数)的退出状态:每一条命令或函数,在退出时都会返回一个小的整数值给调用它的程序。

在 shell 的判断语句中,条件(condition)实际上是语句列表而不是一般的布尔表达式。通常退出状态 0 表示函数或命令执行成功,非 0 数表示失败。
shell 语法允许在逻辑上操作退出状态,常见的有 NOT,AND 和 OR。

NOT 操作符是 !,在 condition 条件判断后,用 ! 取反,再测试选择执行语句。AND 操作符是 &&,先判断 condition1,成功之后再判断 condition2,如果两个都判断成功,则整个判断语句成功。OR 操作符是 ||,只要两个或多个条件中有一个成功,则整个判断语句成功。AND 和 OR 都是短路运算符,即只要判断出整个语句的真假,则直接返回,不向后继续判断,即使后面的语句根本无法执行。

if 语句唯一可以测试的内容是退出状态,不能用于检测表达式的值。但是通过 test 命令或 [...]的语法检测,此时“[”后面和“]”前面必须有空格。

shell 支持字符串的比较,结合 test 或[ ... ]命令能判断判断比较结果,然后再进行相关操作。

将第一个位置参数传递给 test.sh,当 $1 不存在时,显示一条出错信息,如果 $1 存在且大于 0,则无显示。-s 参数与文件名之间必须要有一个空格。$1 两边的引号确保即使它为一个空字符串,程序要能正常运行。

如果给出的位置参数小于 2 或 $1 指定的文件不存在,则退出。



首先,判断文件是否为目录;如果不是目录,则判断文件是否存在;如果文件存在,则判断文件是否具有读写执行的权限,通过则显示 echo 语句;以上所有判定都不通过时,显示 echo 语句。
可以使用逻辑操作符连接带参数的判断语句,也可以使用逻辑操作符将表达式和 shell 命令组合在一起。
case 也是一个流程控制结构,shell 中的 case 语句可以依据可包含通配符的模式测试字符串。通常可以使用 if-elif 语句配合 test 实现同样的功能,但是当选择数目过多时,就会体现出语句太长的局限性。

从语法中可以看出,任何 pattern 之间都可以由 | 分割的几个模式组成,这种情况下 expression 匹配其中任意一个模式则执行相应语句。模式匹配按顺序依次执行,知道匹配上为止,如果无法匹配,则不执行任何操作。
case 语句与 fi 语句一样,结束时是通过字符串颠倒(reverse)。

判断文件后缀,根据不同后缀选择不同的读取方式,最后一个 * 匹配所有其他匹配不上的形式,相当于 C 语言中的 default。
循环可以控制某些代码的重复行为或允许对多个对象操作。
for 循环用于遍历整个对象/数字列表,依次执行每个独立对象/数字的循环内容,在 shell 脚本里,对象可以是命令行参数、文件名或者任何可以以列表格式建立的东西。


两个例子都可以遍历 mp3 文件并且依次播放。但是使用 find 命令会层层深入文件夹依次查找,而直接列出只会包含当前目录的文件夹。执行反单引号(``)之前的命令,引用结果作为字符串。for 循环中如果 in list 参数被省略,则默认为 in "$@",即命令行参数的引用列表。




在 shell 中经常使用 while true 或者 until false 来构建无限循环。continue 语句用于在循环体中提早开始下一轮循环,break 语句用于跳出整个循环,而 continue 与break 语句也弥补了 shell 中没有 goto 的不足。在多层循环中,continue n 表示会把 n 层的剩余代码都去掉,break n 表示退出 n 层循环。
文章名称:Shell编程从入门到精通-第03章
文章路径:http://scpingwu.com/article/pogjjs.html