shell脚本进阶—语法篇

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/summy_J/article/details/75126049

ForeWord

Question:

如果把C语言的各种数据类型、指针、结构体、联合体等结构全都去掉,还剩下什么?

……
1

没错,还有条件判断、循环、一维数组(因为没有指针)以及部分函数。
而这些,正是shell语法结构中包含的所有内容。

所以我们可以看出,shell语法学习起来远比C语言容易得多。

那么本文就简单总结下shell语法的内容及其具体使用方法。

Key Points:

  • 条件判断
  • 循环语句
  • 位置参数和特殊变量
  • Shell脚本调试选项
  • 函数
  • 数组

        ~tips:全文阅读需10min~
    

Part 1:条件判断

1. test & [

首先你没有看错,[ 也是一个命令。它和test命令都被用来测试条件是否成立,使用方法和场景如下:

1.测试数字和字符串

先编写脚本程序test.sh:
2

然后sh test.sh运行:
3

这里的 ][命令的参数。

其中各选项解释如下:

选项 含义
-eq(equal) 等于
-ne(not equal) 不等于
-gt(great) 大于
-ge 大于等于
-lt(little) 小于
-le 小于等于


有没有发现,这里的判断结果与C语言刚好相反呢?

       没错,用test和[判断时,如果测试结果为真,返回0;结果为假则返回1.

为什么要这样设置呢?

       shell脚本中,所有的语句都被看作一条命令,它只关心命令执行的对不对。所以条件判断时并不直接看语句是否成立,而是要看命令的退出码(Exit Status)。在linux中如果命令执行正确,返回码就是0,所以没有必要专门为条件判断改变这一习惯。进而才有结果为真返回0的特点。

此外,还可以看出:命令test或 [ 的参数形式是相同的,只不过test命令不需要]参数。

字符串还可以这样判断:

56

运行:
47

还有这样:

15

运行:

16

由于[比test更简洁。所以一般推荐使用[来进行条件测试,当然,如果你喜欢用test,我也没意见。。。

2.其它选项

除了判断数字和字符串以外,还可以判断目录类型以及其他的东西。这也自然涉及到了目录类型的选项。具体见下例:

165

5

选项当然远远不止这些,光目录的选项就有很多,大家可以自行百度了解。但用法就如上例。

3. 与、或、非的测试命令

逻辑上的与或非也是条件测试的重点,用法如下:

46

运行结果:
491874

2. if/then/elif/else/fi

   和C语言类似,在Shell中用if、then、elif(elseif)、else、fi这几条命令实现分支控制。这种流程控制语句本质上也是由若干条Shell命令组成的。

2

3

注意:

1.如果两条命令写在同行则需要用;号隔开
2.then后面有换行,若不换行,Shell会认为这条命令没写完进而自动续行,把下一行接在then后面当作一条命令处理。
3.和[命令一样,要注意命令和各参数之间必须用空格隔开。
4.if命令的参数组成一条子命令为真则执行then后面的子命令,否则执行elif、else或者fi后面的子命令。
5.if后面的子命令通常是测试命令,但也可以是其它命令。
6.Shell脚本没有{}括号,所以用fi表示if语句块的结束。
7.分支语句内容不能为空,否则会出错。

5

如果你实在什么都不想写,可以在if后加:表示空语句

68

此外,,Shell还提供了&&和||语法,作用类似于if语句。
其中,&&相当于“if…then…”,而||相当于“ifnot…then…”。

275

&&和||用于连接两个命令,而上面讲的-a 和-o仅用于在测试表达式中连接两个测试条件,要注意它们的区别:

27

3. case/esac

  case命令可类比C语言的switch/case语句,esac表示case语句块的结束。不同的是:

1. C语言的case只能匹配整型或字符型常量表达式,而Shell脚本的case可以匹配几乎任意类型,且每个匹配分支可以有若干条命令,末尾必须以;;结束。
2. 语句执行时找到第一个匹配的分支并执行相应的命令,然后直接跳到esac之后,不需要像C语言一样用break跳出。
164


Part 2:循环语句

1. for/do/done

Shell脚本的for循环结构和C语言很不一样,使用方法有2种:

16574

个人推荐第二种,因为习惯了。

2. while/do/done

Shell中的while循环也类似C语言。但用法上依然略有不同:

这里写图片描述1654

3. until

Shell中的until循环相当于C语言的do..while循环,使用方法如下:

654


Part 3:位置参数和特殊变量

shell中定义了脚本文件的未知参数并对多个特殊变量进行自动赋值,使他们表示特定的含义,这对编写脚本程序带来了很多益处。

1. $系列

最常用的就是下表中给出的项目:

项目 含义
$0 相当于C语⾔main函数的argv[0]
$1/2… 位置参数,相当于C语⾔main函数的argv[1]、argv[2]
$# 位置参数的个数,相当于C语⾔main函数的argc-1,注意这⾥的#后⾯不表示注释
$@ 表示整个位置参数列表
$? 上一条命令的退出码
$$ 当前shell脚本的进程号

167

2. shift命令

位置参数可以⽤shift命令左移。且只将位置参数左移,前边移出的抛弃。$0不变。例如:

1654


Part 4:shell调试选项

Shell提供了一些用于调试脚本的选项,如下表所示:

选项 作用
-v 读⼀遍脚本中的命令但不执⾏,⽤于检查脚本中的语法错误
-x 提供跟踪执⾏信息,将执⾏的每⼀条命令和结果依次打印出来

使⽤这些选项有三种⽅法(以-x为例)

⼀是在命令行提供参数$ sh -x test.sh:
13675

⼆是在脚本开头提供参数! /bin/sh -x:
3318

第三种方法是在脚本中⽤set命令启⽤或禁⽤参数:
1357

其中,set -x和set +x分别表⽰启用和禁⽤-x参数,这样可以只对脚本中的某⼀段进⾏跟踪调试。


Part 5:函数

和C语言类似,Shell中也有函数的概念。但是函数定义中没有返回值也没有参数列表。

36571

  1. 注意函数体的左花括号 { 和后面的命令之间必须有空格或换行,如果将最后⼀条命令和右花括号 } 写 在同⼀行,命令末尾必须有;号。

  2. Shell中的函数调用不写括号才就可以执⾏函数体中的命令。

  3. Shell脚本中的函数必须先定义后调用,⼀般把函数定义都写在脚本的前⾯,把函数调⽤和其它命令写在脚本的最后(类似C语⾔中的main函数,这才是整个脚本实际开始执⾏命令的地⽅)

  4. Shell函数没有参数列表并不表示不能传参数,事实上,函数就像是迷你脚本,调⽤函数时可以传任意个参数,即用上面讲到的位置参数来提取参数,函数中的位置参数相当于函数的局部变量,改变这些变量并不会影响函数外⾯的$0/1/2等变量。

函数内部定义的变量并非C语言的局部变量,而更像是在此脚本文件内全局有效的变量。在函数体外也可以访问,如上例中的sum:


3175

如果想要让它起到局部变量的作用,就要加local关键字:

此时,在从外部访问就看不到它的值了:
357168

另外,关于函数退出码的判定,有以下两种方法:

354

最后再给大家安利一行shell代码:

31786

可以记住这条命令,看谁不爽发给谁。。。


Part 6:数组

因为没有指针,所以bash只支持一维数组,但没有限定数组的大小。

类似于C语言,数组元素的下标由0开始编号。获取数组中的元素要利⽤下标,下标可以是整数或算术表达式,其值应⼤于或等于0。

999

  1. 在Shell中,⽤括号来表⽰数组,数组元素⽤“空格”符号分割开
  2. 还可以单独定义数组的各个分量,而且可以不使⽤连续的下标。
  3. 读取数组元素值的⼀般格式是: ${array_name[index]}
  4. 使⽤@ 或 * 可以获取数组中的所有元素

遍历数组元素:

57

运行:

41897165


The End

终于写完啦,最后再给大家安利两个链接,讲了shell脚本中单引号,双引号和反引号的区别,可以了解下:

http://blog.csdn.net/hittata/article/details/8049665
http://blog.csdn.net/miyatang/article/details/8077123

3571526

猜你喜欢

转载自blog.csdn.net/summy_J/article/details/75126049