bash脚本基础
1. 简介
深入了解一些代码之后,发现bash老是阻挡自己的脚步,尤其是一些项目跑在Linux环境下,Coders便会选择写一个shell脚本,想自己改又不是很懂,还有像是Github的action脚本也会用到这些。Shell即贝壳的意思,它就像套在Linux内核的一种抽象接口,对内连接内核,对外为用户提供命令接口,bash便是其中一种 ^1:
Shell 接收到用户输入的命令以后,会根据空格将用户的输入,拆分成一个个词元(token)。然后,Shell 会扩展词元里面的特殊字符,扩展完成后才会调用相应的命令。这种特殊字符的扩展,称为模式扩展(globbing)。
2. 内容
2.1 Shebang 行
脚本的第一行通常是指定解释器,即这个脚本必须通过什么解释器执行。这一行以#!字符开头,这个字符称为 Shebang,所以这一行就叫做 Shebang 行。#!后面就是脚本解释器的位置,Bash 脚本的解释器一般是/bin/sh或/bin/bash。
1 |
2.2 脚本参数
调用脚本的时候,脚本文件名后面可以带有参数:
1 | ./script.sh word1 word2 word3 |
script.sh是一个脚本文件,word1、word2和word3是三个参数。而脚本文件内部,可以使用特殊变量,引用这些参数:
| 参数 | 意义 |
|---|---|
$0 |
脚本文件名,即script.sh。 |
$1~$9 |
对应脚本的第一个参数到第九个参数。 |
$# |
参数的总数。 |
$@ |
全部的参数,参数之间使用空格分隔。 |
$* |
全部的参数,参数之间使用变量$IFS值的第一个字符分隔,默认为空格,但是可以自定义。 |
如果脚本的参数多于9个,那么第10个参数可以用${10}的形式引用,以此类推。注意,如果命令是command -o foo bar,那么-o是$1,foo是$2,bar是$3。
2.3 条件判断
if是最常用的条件判断结构,只有符合给定条件时,才会执行指定的命令。它的语法如下。
1 | if commands; then |
以fi结尾,if结构的判断条件,一般使用test命令:
1 | # 写法一 |
写法1太繁琐,方便起见使用第二种形式:
| 命令 | 解释 |
|---|---|
[ -a file ] |
如果 file 存在,则为true |
[ -b file ] |
如果 file 存在并且是一个块(设备)文件,则为true |
[ -c file ] |
如果 file 存在并且是一个字符(设备)文件,则为true |
[ -d file ] |
如果 file 存在并且是一个目录,则为true |
[ -e file ] |
如果 file 存在,则为true |
[ -f file ] |
如果 file 存在并且是一个普通文件,则为true |
[ -g file ] |
如果 file 存在并且设置了组 ID,则为true |
[ -s file ] |
如果 file 存在且其长度大于零,则为true |
| 命令 | 解释 |
|---|---|
[ -n string ] or [ string ] |
如果string不为空(长度大于0),则判断为真 |
[ -z string ] |
如果字符串string的长度为零,则判断为真 |
[ string1 == string2 ] |
如果string1和string2相同,则判断为真 |
[ string1 != string2 ] |
如果string1和string2不相同,则判断为真 |
[ string1 '>' string2 ] [^2] |
如果按照字典顺序string1排列在string2之后,则判断为真。 |
[ string1 '<' string2 ] |
如果按照字典顺序string1排列在string2之前,则判断 |
| 命令 | 解释 |
|---|---|
[ integer1 -eq integer2 ] |
如果integer1等于integer2,则为true |
[ integer1 -ne integer2 ] |
如果integer1不等于integer2,则为true |
[ integer1 -le integer2 ] |
如果integer1小于或等于integer2,则为true |
[ integer1 -lt integer2 ] |
如果integer1小于integer2,则为true |
[ integer1 -ge integer2 ] |
如果integer1大于或等于integer2,则为true |
[ integer1 -gt integer2 ] |
如果integer1大于integer2,则为true |
2.4 数组
bash数组的定义:
1 | # 变量定义的`=`前后不要有空格,否则会被解释为命令,而数组元素定义用空格分割 |
数组元素选取:
${array[i]}:取第i个元素${array[@]}:读取所有元素array+=(d e f):追加元素d、e、f
还有一种数组在bash中叫关联数组,其实就是(key,value)键值对集合即字典:
1 | declare -A colors |
${colors["blue"]}:字典读取
2.5 循环
这里只介绍一种格式,其余都是类似的:
1 | number=0 |
和其他语言一样,亦可以使用continue和break,另外还有一种特别的循环类型:
1 | select name in list |
这种方式是bash中特有的,运行后会出现一个单选框,只能选择其中一个:
1 |
|
2.6 函数
函数的定义和其他语言一样:
1 | function fn() { |
函数定义的定义也与其他语言一样,function关键字可写可不写,在函数体内定义局部变量则用local关键字,如果不使用local直接定义,则为全局变量(尽管在函数体内)。
3. Reference
[^2]: test命令内部的>和<,必须用引号引起来(或者是用反斜杠转义)。否则,它们会被 shell 解释为重定向操作符