一.shell脚本简介
Shell脚本,就是利用Shell的命令解释的功能,对一个纯文本的文件进行解析,然后执行这些功能,也可以说Shell脚本就是一系列命令的集合。Shell可以被称作是脚本语言,因为它本身是不需要编译的,而是通过解释器解释之后再编译执行,和传统语言相比多了解释的过程所以效率会略差于传统的直接编译的语言。Shell可以直接使用在win/Unix/Linux上面,并且可以调用大量系统内部的功能来解释执行程序,如果熟练掌握Shell脚本,可以让我们操作计算机变得更加轻松,也会节省很多时间。
Shell能做什么
- 将一些复杂的命令简单化(平时我们提交一次github代码可能需要很多步骤,但是可以用Shell简化成一步)
- 可以写一些脚本自动实现一个工程中自动更换最新的sdk(库)
- 自动打包、编译、发布等功能
- 清理磁盘中空文件夹
- 总之一切有规律的活脚本都可以尝试一下
Shell不能做什么
- 需要精密的运算的时候
- 需要语言效率很高的时候
- 需要一些网络操作的时候
- 总之Shell就是可以快速开发一个脚本简化开发流程,并不可以用来替代高级语言
二.shell脚本使用
1.变量/常见的数据类型
- 变量定义与赋值的标准形式是
标识符=值
,不需要单独声明,等号附近(前后)不能有空格,示例如下:
#!/bin/bash
a=1
name="hahaha"
_o="o"
_ld='ld'
_old="$_o$_ld" # 通过 `$` 来引用变量 (此处只能使用双引号),字符串拼接
_old2=$_o""$ld #结果与上面的相同,输出结果都为old
echo $name is $a years $_old($_old2) # 输出为hahaha is 1 years old(old)
unset _o # 删除变量(置空)
- 常见数据类型
(1)数组
定义:declare -a arrayName
1、赋值
arrayName[IDX]=value #单个元素赋值
arrayName=([IDX]=value [IDX]=value) #部分元素赋值
arrayName=(value1 value2 value3) #所有元素完全赋值
2、引用
${arrayName[IDX]} #引用单个元素,不指定下标则表示引用第0个元素
${arrayName[@]} #引用所有元素,也可用${arrayNanme[*]}
${#arrayName[@]} #返回数组元素个数,也可用${#arrayName[*]}
3、切片
${arrayName[@]:offset:number} #偏移offset个元素(从下标为offset的元素开始),共number个
4、撤销、追加元素
arrayName[${#arrayName[@]}]=value #在数组最后追加一个元素并赋值
unset arrayName[IDX] #撤销某个元素,不会将其后面的元素下标向前推进1,但是在使用${#arrName[@]}时,数组元素个数会减1,即变为稀疏数组
实例:
#!/bin/sh
array=(1 2 3 4 5) #定义数组,用空格分开
array2=(aa bb cc dd ee) #定义数组
value=${array[3]} #找到某一个下标的数,然后赋值
echo $value #打印 4
value2=${array2[3]} #找到某一个下标的数,然后赋值
echo $value2 #打印 dd
length=${#array[*]} #获取数组长度
echo $length 5
(2)字符串
- 切片
${varName:offset:number} #偏移offset个字符向后取number个字符
例:str=abcabc #后文均使用该变量演示
echo ${str:1:3} #输出bca
${varName:offset} #偏移offset个字符取至末端
例:echo ${str:2} #输出cabc
${varName: -number} #取末端number个字符
例:echo ${str: -2} #输出bc,冒号后必须跟空格
- 按模式匹配取子串
${varName#*word} #从左至右匹配,删除第一次匹配到word字符及之前的所有字符
例:echo ${str#*b} #输出cabc
${varName##*word} #从左至右匹配,删除最后一次匹配到word(字符)及之前的所有字符
例:echo ${str##*b} #输出c
${varName%word*} #从右至左匹配,删除第一次匹配到word字符及之前的所有字符
例:echo ${str%b*} #输出abca
${varName%%word*} #从右至左匹配,删除最后一次匹配到word字符及之前的所有字符
例:echo ${str%%b*} #输出a
- 查找替换
${varName/pattern/substi} #查找变量中第一次匹配到的pattern字符串替换为substi
例: echo ${str/bc/d} #输出adabc
${varName//pattern/substi} #查找变量中所有匹配到的pattern字符串替换为substi
例: echo ${str//bc/d} #输出adad
${varName/#pattern/substi} #查找行首被pattern匹配的内容替换为substi
例:echo ${str/#ab/dd} #输出ddcabc
${varName/%pattern/substi} #查找行尾被pattern匹配的内容替换为substi
例:echo ${str/%bc/dd} #输出abcadd
注:删除则为不指定substi,如echo ${str//ab},输出cc。
- 其他
${varName:-value} #如果varName为空则返回value,并不会修改变量本身,输出的value是命令执行结果
${varName:=value} #如果varName为空,则返回value并赋值给varName,不为空则返回其本省值,等同于varName=${varName:-value}
${varName:+value} #如果varName为空不做处理,不为空则返回value,varName本身不变
${varName:?errorInfo} #varName如果为空则返回errorInfo,并会输出到错误输出中,不为空则返回其原值
${varName^^} #将字符串中的小写字母转为大写字母
${varName,,} #将字符串中的大写字母转为小写字母
实例:
#!/bin/sh
mtext="hello" #定义字符串
mtext2="world"
mtext3=$mtext" "$mtext2 #字符串的拼接
echo $mtext3 #输出字符串 hello world
echo ${#mtext3} #输出字符串长度 11
echo ${mtext3:1:4} #截取字符串 ello
2.流程控制(判断/函数/循环)
(1)判断
与c很像,也存在if...else ,if ....elseif...,case等形式
#!/bin/sh
a=10
b=20
if [ $a == $b ]
then
echo "true"
fi ###与if then配套使用
(2)循环
也存在for和while两种循环形式,以及break、continue等操作
#!/bin/sh
for i in {1..5}
do
echo $i
done
COUNTER=0
while [ $COUNTER -lt 5 ]
do
COUNTER=`expr $COUNTER + 1`
echo $COUNTER
done ###与do配套使用
(3)函数
#!/bin/sh
test(){
aNum=3
anotherNum=5
return $(($aNum+$anotherNum))
}
test
result=$? ###$? 是一个特殊变量,用来获取上一个命令的退出状态,或者上一个函数的返回值。
echo $result ###8
test2(){
echo $1 #接收第一个参数
echo $2 #接收第二个参数
echo $3 #接收第三个参数
echo $# #接收到参数的个数
echo $* #接收到的所有参数
}
test2 aa bb cc
3.混合运算与括号
- 运算
运算符 | 含义 |
---|---|
= | 两个字符串相等返回true |
!= | 两个字符串不相等返回true |
-z | 字符串长度为0返回true |
-n | 字符串长度不为0返回true |
-d file | 检测文件是否是目录,如果是,则返回 true |
-r file | 检测文件是否可读,如果是,则返回 true |
-w file | 检测文件是否可写,如果是,则返回 true |
-x file | 检测文件是否可执行,如果是,则返回 true |
-s file | 检测文件是否为空(文件大小是否大于0,不为空返回 true |
-e file | 检测文件(包括目录)是否存在,如果是,则返回 true |
- 括号
双小括号(( ))
用于算术(整型)运算,同时也可以用于一些特殊功能
a=2
b=$(( ($a + 1) / 2 )) # => b = (2 + 1) / 2 = 1
rd=$((RANDOM % 100)) # => rd 为0~99的随机数
c=$(( $a > 1 )) # => 判断 a > 1 ,结果为 1 (true)
d=$(expr $a + $b) # => 等价于 $(($a + $b))
中括号[ ]
和双中括号[[ ]]
用于比较运算,其中[ ]
实际上是对linux中test
命令的隐式调用(务必注意:在shell的定义中,true
为0,而false
为1)
a=2; b=1; c=3; # 单行可以用分号隔开多个表达式
str='ray-tracing'
[ $a -gt $b ] # 两边一定要空格, [$a -gt $b] 是不合法的
echo $? # 比较结果存储于 $? 中 => 输出为 0 (true)
[ $c -eq $c ] # 等价于 test $c -eq $c
echo $? # 输出为 0 (true)
[ $a -ne 1 -a $c -eq 3 ] # 相当于表达式 a != 1 && c == 3
[ $a -ne 1 -o $c -ne 3 ] # 相当于表达式 a != 1 || c != 3
[ $str != 'ray-tracing' ] # 结果为 1 (false)
[ $str = 'ray' ] # 结果为 1 (false)
[[ a + b = 3 && a != b ]] # 结果为 0 (true)
# 此语句只有 bash 下可用
不难看出,双中括号[[ ]]
相比中括号更加人性化,可以轻松胜任近似C语言
的表达式。
大括号{}
用于定义范围和通配,在此暂不详细阐述,有兴趣的读者可以参阅这篇博客。
4.命令与IO
命令与IO是shell
脚本中最重要的部分,在管道系统的帮助下,脚本可以很轻松地与系统命令和程序交互。实例如下:
txts=`ls | egrep *.\.txt` # 执行ls列出当前目录文件,并用egrep筛选.txt文件
# 还可以写作 txts=$(ls | egrep *.\.txt)
echo $txts # 输出所有 txt 文件
text=`cat hello.txt` # => text 被赋值为 hello.txt 里的文本
username=`whoami` # => username 被赋值为当前用户名
echo $username # => 输出用户名,如 root
text1="hello,"
text2="world!"
echo -n $text1 > hello.txt # 利用重定向输出 (n 表示不换行)
echo $text2 >> hello.txt # 追加文本到hello.txt中
####从控制台读取
# A + B Problem ~
read a
read b
c=$(($a+$b))
echo $a + $b = $c # => e.g. 1 + 3 = 4
值得注意的是,变量也可以参与`符号所包含的命令中,比如
text="eureka!"
text=`echo $text | tr 'a-z' 'A-Z'` # 用tr替换所有小写字母为大写字母
echo $text
补充:
(1)定向输入
$echo result > file #将结果写入文件,结果不会在控制台展示,而是在文件中,覆盖写
$echo result >> file #将结果写入文件,结果不会在控制台展示,而是在文件中,追加写
echo input < file #获取输入流
(2)一些特殊的运算符
- 文件比较运算符
test $[num1] -eq $[num2] #判断两个变量是否相等 test num1=num2 #判断两个数字是否相等
参数 | 含义 |
---|---|
-e file | 文件存在则返回真 |
-r file | 文件存在并且可读则返回真 |
-w file | 文件存在并且可写则返回真 |
-x file | 文件存在并且可执行则返回真 |
-s file | 文件存在并且内容不为空则返回真 |
-d file | 文件目录存在则返回真 |
- 正则表达式
正则表达式(或称Regular Expression,简称RE)就是由普通字符(例如字符 a 到 z)以及特殊字符(称为元字符)组成的文字模式。该模式描述在查找文字主体时待匹配的一个或多个字符串。正则表达式作为一个模板,将某个字符模式与所搜索的字符串进行匹配。简单的说,正则表示式就是处理字符串的方法,它是以行为单位来进行字符串的处理行为,正则表示式通过一些特殊符号的辅助,可以让使用者轻易的达到搜寻/删除/取代某特定字符串的处理程序。vim、grep、find、awk、sed等命令都支持正则表达式。
具体的可以参考这篇博客:https://blog.csdn.net/kangshuo2471781030/article/details/79220259
参考链接:
https://www.cnblogs.com/snake23/p/9477440.html(一篇文章让你快速入门 学懂Shell脚本)
https://blog.csdn.net/wxx1237/article/details/87188420(Shell脚本快速入门)