shell编程入门(bash)
一、背景知识
(1)什么是shell?
高大上的解释,往往让人摸不住头脑。一句话概括就是:shell编程就是对一堆Linux命令的逻辑化处理。
(2)为什么需要shell?
譬如我们要在linux下创建一个文件a.c,可以touch a.c 但是如果我现在是用在linux下创建100个文件,分别为a1.c a2.c.....a100.c 如果这时候还是手工去命令行下执行命令创建也可以,但是很累。最好的做法就是把创建过程写成一个shell脚本程序(for循环),然后去执行这个shell脚本程序,执行这个程序的效果和手工在命令行输入那些命令效果一样的。
(3)如何运行shell(.sh)程序?
第一种:./xx.sh,和运行二进制可执行程序方法一样。这样运行shell要求shell程序必须具有可执行权限。chmod a+x xx.sh来添加可执行权限。
第二种:source xx.sh,source是linux的一个命令,这个命令就是用来执行脚本程序的。这样运行不需要脚本具有可执行权限。
第三种:bash xx.sh,bash是一个脚本程序解释器,本质上是一个可执行程序。这样执行相当于我们执行了bash程序,然后把xx.sh作为argv[1]传给他运行。
(4)linux下常用的shell解释器有哪些?
sh,bash,dash等.。
二、入门
(1)第一个程序
#!/bin/bash
echo "hello world."
shell中#符号表示注释。shell的第一行比较特殊,一般都会以#!开始来指定使用的shell类型。在linux中,除了bash shell以外,还有很多版本的shell, 例如zsh、dash等等...不过bash shell还是我们使用最多的。
echo是linux中的输出命令,该行的意思很明显的就是输出hello world!
(2)创建文件夹和文件
#!/bin/bash
mkdir test
cd test
touch a.txt
cd ..
通过这个脚本大家可以切实感受到shell编程就是linux命令的逻辑组合而已!!
三、变量和引用
(1)变量定义和初始化。
shell是弱类型语言(语言中的变量如果有明确的类型则属于强类型语言;变量没有明确类型就是弱类型语言),和C语言不同。在shell编程中定义变量不需要制定类型,也没有类型这个概念。
(2)变量定义时可以初始化,使用=进行初始化赋值。在shell中赋值的=两边是不能有空格的。
(3)变量赋值,变量定义后可以再次赋值,新的赋值会覆盖老的赋值。shell中并不刻意区分变量的定义和赋值,反正每个变量就是一个符号,这个符号的值就是最后一个给他赋值时的值。
(4)变量引用。shell中引用一个变量必须使用$符号,$符号就是变量解引用符号。
注意:$符号后面跟一个字符串,这个字符串就会被当作变量去解析。如果这个字符串本身没有定义,执行时并不会报错,而是把这个变量解析为空。也就是说在shell中没有被定义的变量其实就相当于是一个定义并赋值为空的变量。
注意:变量引用的时候可以$var,也可以${var}。这两种的区别是在某些情况下只能用${var}而不能简单的$var
shell编程中分为两种变量,第一种是我们自己定义的变量(自定义变量),第二种是Linux已定义的环境变量(环境变量, 例如:$PATH, $HOME 等..., 这类变量我们可以直接使用)。
程序实例:
#!/bin/bash
echo $PATH
#自定义变量hello
hello="hello world"
echo $hello
运行结果如下:
aaa@qq.com:/mnt/hgfs/share/bash$ source var.sh
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/work/tools/gcc-3.4.5-glibc-2.3.6/bin
hello world
注意:shell中无引号、单引号和双引号的区别
(1)shell中使用字符串可以不加双引号,直接使用。而且有空格时也可以,但是缺陷是不能输出"或者其他转义字符。
(2)shell中也可以使用单引号来表示字符串,也是直接使用的,不能输出转义字符
(3)单引号中:完全字面替换(不可包含单引号本身)
(4)双引号中:
$加变量名可以取变量的值
反引号仍表示命令替换
\$表示$的字面值 输出$符号
\`表示`的字面值
\"表示"的字面值
\\表示\的字面值
除以上情况之外,在其它字符前面的\无特殊含义,只表示字面值。
四、shell中调用linux命令
(1)直接执行
(2)反引号括起来执行。有时候我们在shell中调用linux命令是为了得到这个命令的返回值(结果值),这时候就适合用一对反引号(键盘上ESC按键下面的那个按键,和~在一个按键上)来调用执行命令。
程序实例:
#!/bin/bash
path=`pwd`
file=`ls`
echo "path = $path"
echo "file = $file"
执行结果:
aaa@qq.com:/mnt/hgfs/share/bash$ source cmd.sh
path = /mnt/hgfs/share/bash
file = 2.2.1.hello.sh
2.2.2.shell1.sh
2.2.4.shell2.sh
2.2.5.loop.sh
2.2.6.case.sh
2.2.8.Makefile
2.2.9
b.c
cmd.sh
test
var.sh
五、选择分支
(1)if分支结构
让我们先看一下MAN手册是怎么介绍if命令的:
可以看出,if后面跟着的是一个命令,而不是像其他语言那样返回布尔值(true,false)的表达式。通过MAN手册的介绍我们可以知道:在shell脚本的if其实是根据紧跟后面的那个命令的退出状态码来判断是否执行then后面的语句的。
关于退出状态码,你只需要记住:正常退出(命令执行正常)的状态码是0, 非正常退出的状态码不是0(有不少)。
以上语句的语义为: 如果if后面的命令执行正常(状态码0),那么就执行then后面的语句。否则不执行。 fi代表if语句的结束。
例如:
1 #!/bin/bash
#这儿由于pwd是linux内置的命令,因此执行后会正常退出(状态码0),所以会执行then中的语句
#如果此处替换为一个不存在的命令(例如: pw),那么就会非正常退出,不会执行then中的语句
2
3 if pwd
4 then
5 echo "OK"
6 else
7 echo "error"
8 fi
程序最终输出OK
那么你可能会问了,我要是就是想像C语言那样判断一个表达式是否成立怎么办呢?客官别着急,有以下两种解决办法:
(1)使用test命令
test EXPRESSION ,test后面跟着的是一个表达式,如果表达式成立,就会退出并返回退出状态码0,否则返回非0。这样,我们就可以借助test命令来实现if对表达式的判断了。一个典型的格式如下:
if test expression
then
commands
else
commands
fi
表达式成立就执行then语句,否则else语句。值得注意的是:
test命令只能判断一下三类条件:
- 数值比较
- 字符串比较
- 文件比较
数值比较
(-eq)、大于(-gt)、小于(-lt)、大于等于(-ge)、小于等于(-le)
例如:
1 #!/bin/bash
2
3 num1=10
4 num2=20
5
6 if test $num1 -gt $num2
7 then
8 echo "num1>num2"
9 else
10 echo "num1<=num2"
11 fi
12
执行结果:
num1<=num2
字符串比较
注意:这个测试相等只有一个等号
例如:
1 #!/bib/bash
2
3 str1=test
4 str2=test
5
6 if test $str1 = $str2
7 then
8 echo equal
9 else
10 echo "not equal"
11 fi
12
输出结果:
equal
文件比较
文件比较的命令很多,大家可以查看man手册来进行学习,常用的就是 -f ,即判断文件是否存在
(2)使用双括号和双方括号
- 使用双括号
可以看到使用test命令判断数字逻辑的时候必须符合其命令的规范,需要用到-gt、-eq等,可不可以直接像C语言那样呢?答案是可以的,我们只需要在表达式外边加双括号,但是值得注意的是:括号里面两边都需要有空格,而且(())中变量是可以不使用$来引用的
双括号命令允许你在比较过程中使用高级数学表达式。关键是使用双括号,咱就可以用数学比较符号啦(等于==, 大于>, 小于< 等等都能使用啦)
例1:
1 #!/bin/bash
2
3 num1=10
4 num2=20
5
6 if (( num1 == num2 ))
7 then
8 echo "num1==num2"
9 else
10 echo "num1!=num2"
11 fi
12
输出num1!=num2
例2:
1 #!/bin/bash
2
3 num1=10
4 num2=10
5
6 if (( $num1 == $num2 ))
7 then
8 echo "num1==num2"
9 else
10 echo "num1!=num2"
11 fi
12
输出num1=num2
- 使用双方括号
双方括号命令提供了针对字符串比较的高级特性。它不仅解决了使用test所带来的一系列毛病,还提供了一些test命令所没有的高级用法。测试相等同样可以使用==。
例1:
1 #!/bib/bash
2
3 str1=haha
4 str2=haha
5
6 if [[ $str1 = $str2 ]]
7 then
8 echo equal
9 else
10 echo "not equal"
11 fi
12
输出equal
例2:
1 #!/bib/bash
2
3 str1=haha
4 str2=hahe
5
6 if [[ $str1 = $str2 ]]
7 then
8 echo equal
9 else
10 echo "not equal"
11 fi
12
输出:not equal
补充:
if判断式中使用“-o”表示逻辑或,“-a”表示逻辑与
相当于C语言中在if后面的条件式中用逻辑与、逻辑或来连接2个式子,最终的if中是否成立取决于2个式子的逻辑运算结果。
(2)case结构
可以用case语句匹配一个值与一个模式,如果匹配成功,执行相匹配的命令。case语句格式如下:
case 值 in
模式1)
command1
command2
...
commandN
;;
模式2)
command1
command2
...
commandN
;;
*)
command1
command2
...
commandN
;;
esac
case工作方式如上所示。取值后面必须为单词in,每一模式必须以右括号结束。取值可以为变量或常数。匹配发现取值符合某一模式后,其间所有命令开始执行直至 ;;。
取值将检测匹配的每一个模式。一旦模式匹配,则执行完匹配模式相应命令后不再继续其他模式。如果无一匹配模式,使用星号 * 捕获该值,再执行后面的命令。
实例:
1 #!/bin/bash
2 num=2
3 case $num in
4 1)
5 echo "num=1";;
6 2)
7 echo "num=2";;
8 3)
9 echo "num=3";;
10 4)
11 echo "num=4";;
12 *)
13 echo "defaul";;
14 esac
输出:
num=2
Ref:
下一篇: ARM的栈与栈指令