近段时间学习了一下基本的Linux Shell脚本编程。由于Shell脚本知识本身比较杂乱,再加上各种语法比起目前大家所用的C,C++,Java等各种高级语言来说也有些怪异,并且细节较多,这导致学习完成之后容易忘记,这里记录下来,权且做个备忘录使用。
一、构建基本脚本
1. shell中的数组
(1) 数组的定义
myarray=(one two three four five)
(2) 打印myarray中数组的值:
# echo $myarray ====> one
# echo ${myarray[1]} ====> two
# echo ${myarray[*]} =====> one two three four five
(3) 修改数组的值
# myarray[4] = last
# echo ${myarray[*]} =====> one two three four last
(4) 删除数组元素中的一个值
# unset myarray[2]
# echo ${myarray[*]} =====> one two four five
# echo ${myarray[2]} ======>
从上面可以看出,删除数组元素的某一个值,只是将该位置的数据元素置空,其占位符仍然存在
(5) 删除整个数组
# unset myarray
2: 对命令重命名(注意这里用的
# alias -p myls=‘ls -al'
3:echo显示消息
# echo hello,world
echo显示消息时,一般可以不带单、双引号(如上)。echo命令也可以用单引号或双引号将文本字符圈起来。如果你在字符串中用到了它们,你需要在文本中使用其中一种引号,而用另外一种引号将它们圈起来。例如:
# echo "what's your name"
此外,echo -n参数可以使打印出来的消息禁止换行。
4: 变量
linux中shell可以使用的变量有两种,一种就是所谓的环境变量,另外一种就是所谓的用户变量。变量的定义形式为:
# variable-name=variable-value
一般环境变量用名用大写字母组合,用户变量名用小写字母组合。
使用变量:一般是通过$variable-name 的方式来引用变量。例如:
# echo $variable-name
5:反引号
shell脚本中最有用的特性之一就是反引号(`)。反引号允许你将shell命令的输出赋给变量。尽管看起来并不那么重要,但它却是脚本编程中的一个主要构件。例如:
# test=`date`
# echo $test
6: 重定向
1) 输出重定向
重定向最基本的类型是将命令写到一个文件中。bash shell采用>或者>>来完成这项功能。
2)输入重定向
输入重定向和输出重定向正好相反。输入重定向将文件的内容重定向到命令。bash shell采用< 或者 <<来完成。这里重点介绍一下内联输入重定向<<的使用。使用内联重定向时,需要指定一个文本标记来划分要输入数据的开始和结尾。你可以用任何字符串的值来作为文本标记,但在数据的开始和结尾必须一致。例如:
# wc << EOF
> what are you doing?
> what's your name?
> EOF
7: 管道
8:执行数学运算
1) expr命令
例如:
# expr 1 + 2
但是,有些运算符可能在Linux shell环境下具有一些特殊的含义,因此这可能会出现问题。例如:
# expr 1 | 2
这时需要通过转义符号\来进行转义,使其能够正常工作。
# expr 1 \| 2
2) 使用方括号来进行数学计算
bash shell 为了保持跟Bourne shell 的兼容而包含了expr命令,但是它也同样提供了一个执行数学表达式的更简单的方法。在bash中,在将一个数学运算结果赋给某个变量时,你可以用美元符和方括号( $[ operater ])将数学表达式圈起来。例如:
# var=$[1 + 2]
# echo $var
使用方括号的另一个好处是,你不用担心有些运算符可能在Linux shell中存在的特殊含义,因为其处于方括号内。
但是,bash shell运算符只支持整数运算。如果你要进行任何实际的数学计算, 这是一个巨大的限制。
3) 浮点解决方案
有几种解决方案能够解决bash中数学运算的整数限制。最常见的解决方法是用内建的bash计算器,称作bc。
3.1)bc的基本用法
bash计算器允许你在命令行输入浮点表达式、解释表达式、计算并返回结果的一种编程语言。bash计算器能够识别:
数字(整数和浮点数)变量(简单变量和数组)注释(以#开始的行或C语言中的/**/对)表达式编程语句(例如if-then语句)函数 你可以在shell提示符下通过bc命令访问bash计算器:
浮点运算是由一个内建的称为scale的变量控制的。你必须将这个值设置为结果里你想要的小数后的位数,否则你不会得到你想要的结果。另外,bc还支持变量:
3.2) 在脚本中使用bc
variable=`echo "options; expression" | bc`
4) 退出脚本
shell中运行的每个命令都使用退出状态码来告诉shell它完成了处理。退出状态码是一个0~255之间的整数值,在命令结束运行时由命令传给shell。状态码的设置是通过exit status-code来返回给shell的,你可以通过$?来获取该值。
二、使用结构化命令
1) 使用if-then语句
结构化命令中,最基本的类型就是if-then语句。if-then语句有如下格式:
if command
then
commands
fi
在Bash Shell中,if语句会运行if行定义的那个命令。如果该命令的退出状态码是0(表示该命令运行成功),位于then部分的命令就会被执行。如果该命令的退出状态码是其他什么值,那then部分的命令就不会被执行,bash shell会继续执行脚本中的下一个命令。这里有一个简单的例子:
2) if-then-else语句
语句格式:
if command
then
commands
else
commands
fi
3) 嵌套if
语句格式:
if command1
then
commands
elif command2
then
more commands
fi
4) test命令
到目前为止,你所了解到的if语句中的命令都是普通的shell命令。但是if-then语句只能测试命令的退出状态码。在bash shell中有个好用的工具可以帮你通过if-then语句测试其他条件。test命令提供了在if-then语句中测试不同条件的的途径。如果test命令中列出的条件成立,test命令就会退出并返回状态码0。这样if-then语句就与其他编程语言中的if-then语句以类似的方式工作了。
test命令的格式非常简单:
test condition
condition是test命令要测试的一系列参数和值。当用在if-then语句中时,test命令看起来是这样的:
if test condition
then
commands
fi
bash shell 提供了另一种在if-then语句中声明test命令的方法:
if [ condition ]
then
commands
fi
方括号定义了test命令中用到的条件。注意,你必须在左括号右侧和右括号左侧各加一个空格,否则会报错。test命令可以判断3类条件:
数值比较 字符串比较文件比较 4.1) 数值比较使用test命令最常见的情形是对两个数值进行比较。下面列出了测试两个值时可用的条件参数。
但是,这里需要注意的是,test命令并不能处理浮点数之间的比较。
4.2) 字符串比较
test命令还允许比较字符串的值。比较字符串比较麻烦。下面列出了可用来比较两个字符串值得函数:
4.2.1) 字符串相等性
4.2.2) 字符串顺序
要测试一个字符串是否比另外一个字符串大就变得比较繁琐了。有两个问题会经常困扰正好开始使用test命令的大于小于特性的shell程序员。
大于小于符号必须转义,否则shell会把它们当做重定向符号而把字符串当做文件名;大于小于顺序和sort所采用的不同。 4.2.3) 字符串大小4.3) 文件比较
最后一类测试比较可能是shell编程中最强大的也是最经常用到的比较。test命令允许你测试Linux文件系统上文件和目录的状态。
5) 复合条件测试
if-then语句允许你使用布尔逻辑来组合测试。有两种布尔运算可用:
[ condition1 ] && [ condtion2 ] [ condition1 ] || [ condition2 ] 6) if-then高级特性bash shell有两项较新的扩展,提供了可在if-then语句中使用的高级特性:
用于数学表达式的双尖括号 用于高级字符串处理功能的双方括号 6.1) 使用双尖括号 双尖括号命令允许你将高级数学表达式放入比较中。test命令只允许在比较中进行简单的算术操作。双尖括号命令提供了更多的位用过其他编程语言的程序员所熟悉的数学运算符。下表列出了双尖括号命令中会用到的其他运算符: 例如: 6.2) 使用双方括号 双方括号命令提供了针对字符串比较的高级功能。双方括号命令的格式如下: [[ expression ]] 双方括号里的expression 使用了test命令中采用的标准字符串进行比较。但它提供了test命令未提供的另一个特性-----模式匹配。 例如: 7)case命令 case命令格式如下: case variable in pattern1 | pattern2) commands1;; pattern3) commands2;; *) default commands;; esac 例如: 三、 更多的结构化命令 1) for命令 bash shell提供了for命令,允许你创建一个遍历一系列值的循环。每个迭代都通过一个该系列中的值执行一组预定义的命令。下面是bash shell中for命令的基本格式: for var in list do commands done 在list参数中,你提供了迭代中要用的一系列值。你可以通过几种不同的途径来指定列表中的值。 1.1) 读取列表中的值 1.2) 读取列表中的复杂值 有时候用for循环读取复杂值的时候会出现一些奇怪的问题,例如: 运行结果如下: shell看到了列表值中的单引号并尝试使用它们来定义一个单独的数据值,这个过程一团混乱。 有两种办法解决这个问题: 使用转义字符(反斜线)来将单引号转义使用双引号来定义用到单引号的值 例如: 运行结果如下: 而我们可能会遇到的另一个问题是有多个词的值。记住,for循环假设每个值都是用空格分割的。如果有包含空格的数据值,我们可以通过双引号来将这些值圈起来,这样就会被认为是一个值。例如: 1.3) 从变量读取列表 通常shell脚本遇到的情况是,你将一系列值都集中存储在一个变量中,然后需要遍历整个列表,你也可以通过for命令完成这个: 1.4) 从命令中读取值 例如我们可以从文件中通过cat命令读取出值出来,然后通过for循环显示 1.5)更改字段分割符 这个问题的原因是特殊的环境变量IFS,称为内部字段分隔符(internal field separator)。IFS环境变量定义了bash shell用作字段分割符的一系列字符。默认情况下,bash shell会将下列字符当做字段分隔符: 空格制表符换行符 这里可以通过修改IFS值来更改分割符。但是修改方式有点怪异,比如你要修改成只以换行符来作为分割符的话,可以通过如下方式来更改: IFS=$'\n' 1.6) 用通配符读取目录 你可以用for命令来自动遍历满是文件的目录。进行此操作时,你必须在文件名或路径名中使用通配符。它会强制shell使用文件扩展匹配。文件扩展匹配是生成匹配指定的通配符的文件名或路径名的过程。 例如: 1.7) C语言风格的for命令 1.7.1) C语言的for命令 bash shell 也支持一个版本的for循环,看起来跟C语言风格的for循环类似,虽然它也有一些细微的不同,包括一些会叫shell脚本程序员困惑的东西。如下是bash 中C语言风格的for循环的基本格式: for (( variable assiment; condition; iterator process )) 例如: 1.7.2) 使用多个变量 例如: 1.8) while命令 while命令某种意义上是if-then语句和for循环的混杂体。while命令允许你定义一个要测试的命令,然后循环执行一组命令,只要定义的测试命令返回的是退出状态码。它会在每个迭代的一开始测试test命令。在test命令返回非0退出状态码时,while命令会停止执行那组命令 1.8.1) while的基本格式 while test command do commands done 例如: 1.8.2) 使用多个测试命令 在极少数情况中,while命令允许你在while语句行定义多个测试命令。只有最后一个测试命令的退出状态码会被用来决定什么时候结束循环。 例如: 1.9) until 命令 until命令和while命令工作的方式完全相反。until命令要求你指定一个通常输出非0状态码的测试命令。只有测试命令的退出状态码非0,bash shell才会执行循环中列出的那些命令。until命令的格式如下: until test commands do other commands done 例如: 1.9) 循环控制 1.9.1) break break默认是跳出本层循环。要跳出外层循环可以用break n(其中n为数字). 1.9.2) continue