bash shell文件的开头:
#!/bin/bash
一个简单的bash例子,在屏幕中输出Hello World
#!/bin/bash
echo "Hello world!"
一段简单的Shell
首先来一段简单的Shell脚本,整体上对Shell有一个简单的认识。
上面是一段简单的Shell程序,实现在功能为:
- 在用户主目录下创建一个shell_test文件夹;
- 在用户主目录下创建10个规定命名格式的空文件。
由于是第一个Shell程序,所以有必要逐行解释一下,留下一个好的印象。
- 第一行:指定脚本解释器,这里是用/bin/bash做解释器;
- 第二行:切换到当前用户的home目录;
- 第三行:创建一个名为shell_test的空目录;
- 第四、五行:for循环,一共循环10次;
- 第六行:创建10个名称为test0.txt, test1.txt格式的空文件。
cd、mkdir和touch都是系统自带的程序,一般在/bin目录下;而for、do和done都是Shell的关键字。 Shell中使用#开头的行就是注释。
一个简单的程序之后,我们就开始进入Shell的语法学习吧。
变量
从变量开始学习这段旅程。
基础知识
1. 在Shell中,使用变量之前不需要事先声明,只是通过使用它们来创建它们;
2. 在默认情况下,所有变量都被看做是字符串,并以字符串来存储;
3. Shell变量是区分大小写的;
4. 在Shell中,通过在变量名前加一个$符号来访问它的内容,无论何时想要获取变量内容,都必须在它前面加一个$符号;
下面通过一段Shell脚本来详细的说明上面的内容:
使用read
在Shell中,我们可以使用read命令将用户的输入赋值给一个变量。这个命令需要一个参数,即准备读入用户输入数据的变量名,然后它会等待用户输入数据。通常情况下,在用户按下回车键时,read命令结束。例如以下代码:
引号的使用技巧
在上面的代码中也说了,如果字符串中包含了空格,就需要使用引号将字符串括起来,而这只是引号的一个简单的使用。 像$var1这种的变量在引号中的行为取决于你所使用的引号类型。这句话有以下两层意思:
- 如果把一个$变量表达式放在双引号中,程序执行到这一行时就会把变量替换为它的值;
- 如果把一个$变量表达式放在单引号中,就不会发生替换现象;
但是,我们可以通过在$字符前面加上一个\字符取消它的特殊含义,也就是经常说的转义字符。下面通过一段简单的代码来理解上面内容的意思:
环境变量
当一个Shell脚本程序开始执行时,一些变量根据环境设置中的值进行初始化,一般比较常用的有以下几个:
- $HOME:当前用户的主目录,例如:/home/jelly;
- $PATH:以冒号分隔的用来搜索命令的目录列表;
- $0:Shell脚本的名字;
- $#:传递给脚本的参数个数;
- $$:Shell脚本的进程号,脚本程序通常会用它来生成一个唯一的临时文件。
参数变量
如果脚本程序在调用时带有参数,一些额外的变量就会被创建。即使没有传递任何参数,环境变量$#也依然存在,只不过它的值是0罢了。例如以下实力代码:
输出如下:
BASH 中有一些保留变量,下面列出了一些:
$IFS 这个变量中保存了用于分割输入参数的分割字符,默认识空格。
$HOME 这个变量中存储了当前用户的根目录路径。
$PATH 这个变量中存储了当前 Shell 的默认路径字符串。
$PS1 表示第一个系统提示符。
$PS2 表示的二个系统提示符。
$PWD 表示当前工作路径。
$EDITOR 表示系统的默认编辑器名称。
$BASH 表示当前 Shell 的路径字符串。
$0, $1, $2, ...
表示系统传给脚本程序或脚本程序传给函数的第0个、第一个、第二个等参数。
$# 表示脚本程序的命令参数个数或函数的参数个数。
$$ 表示该脚本程序的进程号,常用于生成文件名唯一的临时文件。
$? 表示脚本程序或函数的返回状态值,正常为 0,否则为非零的错误号。
$* 表示所有的脚本参数或函数参数。
$@ 和 $* 涵义相似,但是比 $* 更安全。
$! 表示最近一个在后台运行的进程的进程号。
条件判断
我们知道,所有程序设计语言的基础是对条件进行测试判断,并根据测试结果采取不同行动的能力。在总结之前,先看看Shell脚本程序里可以使用的条件结构,然后再来看看使用这些条件的控制结构。
一个Shell脚本能够对任何可以从命令行上调用的命令的退出码进行判断,这其中也包括我们写的Shell脚本程序。这就是为什么要在所有自己编写的脚本程序的结尾包括一条返回值的exit命令的重要原因。
test或[命令
在实际工作中,大多数脚本程序都会广泛使用Shell的布尔判断命令[或test。在一些系统上,这两个命令其实是一样的,只是为了增强可读性,当使用[命令时,我们还使用符号]来结尾。写了这么多程序了,还是头一次见,将一个[作为一个命令。算我孤陋寡闻了。下面就通过一个简单的例子来看看test和[是如何使用的。
我们通过使用-f来判断指定文件是否存在。test命令可以使用的条件类型可以归为3类:
- 字符串比较;
- 算术比较;
- 文件相关的条件测试。
下面就分别看看。
字符串比较 | 结果 |
---|---|
string1 = string2 | 如果两个字符串相同,结果就为真 |
string1 != string2 | 如果两个字符串不同,结果就为真 |
-n string | 如果字符串不为空,则结果为真 |
-z string | 如果字符串为一个空串(null),则结果为真 |
算术比较 | 结果 |
---|---|
expression1 -eq expression2 | 如果两个表达式相等,则结果为真 |
expression1 -ne expression2 | 如果两个表达式不等,则结果为真 |
expression1 -gt expression2 | 如果expression1大于expression2,则为真 |
expression1 -ge expression2 | 如果expression1大于等于expression2,则为真 |
expression1 -lt expression2 | 如果expression1小于expression2,则为真 |
expression1 -le expression2 | 如果expression1小于等于expression2,则为真 |
!expression | 表达式为假,则结果就为真;反之亦然 |
文件条件测试 | 结果 |
---|---|
-d file | 如果文件是一个目录,则为真 |
-f file | 如果文件是一个普通文件,则为真;也可以用来测试文件是否存在 |
-r file | 如果文件可读,则结果为真 |
-s file | 如果文件大小不为0,则结果为真 |
-w file | 如果文件可写,则结果为真 |
-x file | 如果文件可执行,则结果为真 |
控制结构
Shell也有一组控制结构,它们与其它程序语言中的控制接口很相似,下面就分开来总结它们。
if语句
结构如下:
代码示例:
elif语句
结构如下
一个很容易出错的问题。例如以下代码:
上面这段代码很简单,运行以下,如果你不输入yes或no,就会运行出错,得到以下提示信息:
这是为何?代码中有if [ $timeofday = "yes" ],当我不输入任何内容时,这个if语句就会变成这样if [ = "yes" ],很明显,这不是一个合法的条件。为了避免出现这种情况,我们必须给变量加上引号,改成这样if [ "$timeofday" = "yes" ]。这样就没有问题了。
for语句
结构如下:
代码示例:
在文章的开头,那段简单的代码中,也包含了for的简单使用。
while语句
结构如下:
代码示例:
until语句
结构如下:
它与while循环很相似,只是把条件测试反过来了;也就是说,循环将反复执行直到条件为真。
case语句
结构如下:
case的代码结构相对来说是比较复杂的。case结构具备匹配多个模式,然后执行多条相关语句的能力,这使得它非常适合于处理用户的输入。下面通过一个实例来看看case的具体使用。
当case语句被执行时,它会把变量input的内容与各字符串依次进行比较。一旦某个字符串与输入匹配成功,case命令就会执行紧随右括号)后面的代码,然后就结束。 在代码中,最后面的*表示匹配任何字符串,我们在写代码时,总是在其它匹配之后再添加一个*以确保如果没有字符串得到匹配,case语句也会执行某个默认动作。 由于case比较复杂,所以不得不再来一段代码,究其用法,如下:
上面这段代码,使用了|符号,也就是说,也就是合并了多个匹配模式;同时还使用了*通配符;没有问题,上面的代码运行的很好。
&&和||操作符
Shell中也支持&&和||符号,和C++语言中的是一样;比如:
从左开始顺序执行每条命令,如果一条命令返回的是true,它右边的下一条命令才能执行。如果此持续直到有一条命令返回false,或者列表中的所有命令都执行完毕;遵循“短路”规则。
从左开始顺序执行每条命令,如果一条命令返回的是false,它右边的下一条命令才能够被执行。如此持续直到有一条命令返回true,或者列表中的所有命令都执行完毕。
语句块
在Shell中也有语句块,使用{}来定义一个语句块。我们可以把多条语句放到一个语句块中执行。
函数
函数,这么NB的东西,Shell怎么能少呢。定义函数的结构如下:
代码示例:
脚本程序从自己的顶部开始执行,当它遇到了foo() {结构时,它知道脚本正在定义一个名为foo的函数。当执行到单独的foo时,Shell就知道应该去执行刚才定义的函数了。函数执行完毕以后,脚本接着foo后的代码继续执行。 当一个函数被调用时,脚本程序的位置参数($*、$@、$#、$1、$2等)会被替换为函数的参数,这也是我们读取传递给函数的参数的方法。当函数执行完毕后,这些参数会恢复为它们先前的值。 我们可以使用local关键字在Shell函数中声明局部变量,局部变量将仅在函数的作用范围内有效。此外,函数可以访问全局作用范围内的其它Shell变量。如果一个局部变量和一个全局变量的名字相同,前者就会覆盖后者,但仅限于函数的作用范围之内,例如以下代码:
输出如下:
用 BASH 设计简单用户界面
BASH 中提供了一个小的语句格式,可以让程序快速的设计出一个字符界面的用户交互选择的菜单,该功能就是由 select 语句来实现的,select 语句的语法为:
select var in
do
statments use $var
done
上面的语法结构在执行后,BASH 会将 中的所有项加上数字列在屏幕上等待用户选择,在用户作出选择后,变量 $var 中就包含了那个被选中的字符串,然后就可以对该变量进行需要的操作了。我们可以从下面的例子中更直观的来理解这个功能:
#!/bin/bash
OPTIONS="Hello Quit"
select opt in $OPTIONS; do
if [ "$opt" = "Quit" ]; then
echo done
exit
elif [ "$opt" = "Hello" ]; then
echo Hello World
else
clear
echo bad option
fi
done
exit 0<span style="font-family:Tahoma, Helvetica, Hei, SimSun, sans-serif;"><span style="font-size: 14px; line-height: 25.2px;">
</span></span>