Shell 编程入门
前言
无论是前端,后端还是移动端,大数据,AI还是运维,等等。作为一个高效的 Coder 都必须掌握 shell 编程。So,本文将告诉,入门 shell 其实很简单,抽点时间就能掌握的高回报率的小技能。
1. 基础知识
1.1 命令行
包行命令和参数的行称为命令行。语法格式如下:
1 | command [arg1] [arg2] ... [argn] RETURN |
其中 command
为命令的名称,arg1 ~ argn
为参数,RETURN
是终止命令行的按键。命令行语法中的方括号表明被括起来的参数为可选项。并不是所有命令都需要参数。选项是一种特殊类型的参数,其前面通常是一个或两个连字符(或称短线,负号:“-”)。多数实用程序的选项前面需要带一个连字符,而 GNU 程序的选项前面通常带有两个连字符。
1.2 shell
本质上,shell 只是执行命令的宏处理器(术语宏处理器是指扩展文本和符号以创建更大表达式的功能)。它既是命令解释器又是编程语言。作为命令解释器,shell 为丰富的 gnu 实用程序集提供用户接口;作为编程语言,允许组合这些实用程序,放在一个脚本文件中(通常后缀为 .sh 也可以不带后缀),构成新的命令,这些新命令具有与 /bin
等目录中的系统命令的具有相同可执行特性,允许用户或搭建立自定义环境以自动化其常见任务,来提高日常开发和运维效率。
shell 的实现有很多种,最常用的是 Bash (Bourne-Again Shell 的缩写),它是 GUN 操作系统的 shell 的解释器,也是本文使用的 shell。
2. test 内置命令
下文需要介绍的条件结构构循环结构,都需要用到 test 内置命令。正确掌握 test 的使用,是应用下文知识的前提。因此,放到前面先介绍。
2.1 格式
test 作为 shell 内置命令,它比较特殊,有两种等效写法:
2.1.1 test 命令方式
1 | test -<opt> args |
反逻辑:
1 | test ! -<opt> args |
2.1.2 中括号方式
比较推荐的使用方式,下文条件和循环结构都采用这种方式。
!!!注意: 中括号两边(与选项和参数之间)要有空格。
1 | [ -<opt> args ] |
反逻辑:
1 | [ ! -<opt> args ] |
2.1.3 示例:判断文件是否存在
test 命令方式:
1 | # 先在当前目录创建一个文件,用于测试 |
中括号方式:
1 | [ -f file.txt ] && echo 'file.txt exist!' |
&&
用于连接多个 shell 命令,只有当前面的命令执行成功,才会执行后面的命令。作用类似 if 。
2.2 其他检查文件的选项
-e
: 检查文件或目录是否存在-d
: 检查目录是否存在-f
: 检查文件是否存在-s
: 检查文件是否存在,以及该文件是否大于0字节-r
: 检查文件是否存在,以及该文件是否可读-w
: 检查文件是否存在,以及该文件是否可写-x
: 检查文件是否存在,以及该文件是否可执行
2.3 数值比较
上一小节列出的选项是检查文件是否存在,只能接受 1 个输入参数。当比较两个数值的关系时,需要用到数值比较选项。
-eq
: 等于-ne
: 不等于-gt
: 大于-ge
: 大于等于-lt
: 小于-le
: 小于等于
示例:
1 | a=1; [ $a -eq 1 ] && echo 'a is equal to 1' |
2.4 字符串比较
字符串比较使用和数值比较不一样的选项,并且只有两种关系:等于和不等于。
=
: 等于!=
: 不等于
示例:
1 | a=hello; [ $a = hello ] && echo 'a is equal to hello' |
需要注意的是当将包含空格的字符串赋值给变量使用时,应该使用如下比较方式。
使用双引号将变量包裹起来:
1 | a='hello world'; [ "$a" = 'hello world' ] && echo 'a is equal to "hello world"' |
或者使用双中括号 [[ … ]] :
1 | a='hello world'; [[ $a = 'hello world' ]] && echo 'a is equal to "hello world"' |
3. 条件结构
3.1 if … then
3.1.1 语法格式
1 | if test-command |
或(更常用的写法):
1 | if test-command; then |
单行写法(将换行符号换成分号):
1 | if test-command; then commands; fi |
3.1.2 示例
保存到 if_test.sh
文件中。
1 | a=1 |
或(可直接在命令行输入):
1 | a=1; if [ $a -eq 1 ]; then echo 'a is equal to 1'; fi |
3.2 if … then … else
3.2.1 语法格式
1 | if test-command; then |
3.2.2 示例
将脚本保存到 if_else_test.sh
文件中。
1 | if [[ $1 = 'hello world' ]]; then |
命令行运行:
1 | $ sh if_else_test.sh 'hello world' |
3.3 if … then … elif
3.3.1 语法格式
1 | if test-command; then |
3.3.2 示例
将脚本保存到 if_elif_test.sh
文件中。
1 | if [ $# -eq 0 ]; then |
命令行运行:
1 | $ sh if_elif_test.sh |
4. 循环结构
4.1 for … in
4.1.1 语法格式
1 | for loop-index in argument-list; do |
4.1.2 示例
将脚本保存到 for_in_test.sh
文件中。
1 | for i in 1 2 3; do |
命令行运行:
1 | $ sh for_in_test.sh |
4.2 while
4.2.1 语法格式
1 | while test-command; do |
4.1.2 示例
将脚本保存到 while_test.sh
文件中。
1 | i=0 |
命令行运行:
1 | $ sh while_test.sh |
5. 变量
shell 中使用变量比较简单,前文也已经多处使用到变量。
5.1 创建
使用 ‘=’ 通过给标识符赋值即可创建变量。需要注意的是等号 ‘=’ 两边不能有空格。
1 | a=1 |
5.2 访问
访问或读取变量,需要在变量标识符前加 ‘$’。
1 | echo $a |
6. 函数
函数是稍后执行(区别于马上执行)的一系列命令的集合。
6.1 语法格式
其中关键字 function
可要可不要。当加上 function
时,函数名后面的圆括号可以省略。和其他语言不同的是,shell 函数不能接受参数,调用时也不能使用圆括号。
1 | function-name() { |
1 | function function-name { |
6.2 示例
将以下脚本保存到文件 func_test.sh
中。
1 | f=$1 |
命令行运行:
1 | $ sh func_test.sh file.txt |
参考
- [1] GNU Bourne Again SHell
- [2] Bash Reference Manual Edition 5.0, for Bash Version 5.0. May 2019