Linux Shell 脚本
shell基础正则表达式
正则表达式是对字符串操作的一种逻辑公式,就是用事先定义好的一些特定字符及这些特定字符的组合,组成一个“规则字符串”,这个“规则字符串”用来表达对字符串的一种过滤逻辑。并规定一些特殊语法表示字符类、数量限定符和位置关系,然后用这些特殊语法和普通字符一起表示一个模式,这就是正则表达式( Regular Expression )
元字符
-
定位符(锚点) --> 匹配文本中的特定位置
元字符 功能 示例 匹配结果说明 ^匹配行首 ^Hello匹配以"Hello"开头的行 $匹配行尾 world$匹配以"world"结尾的行 \b单词边界 \bcat\b匹配独立单词"cat" \B非单词边界 \Bcat\B匹配"scatter"中的"cat" -
字符类 --> 匹配特定字符集合
元字符 功能 示例 匹配结果说明 .匹配任意单个字符 a.c"abc", "adc", "a c"等 [...]匹配括号内任意字符 [aeiou]任意一个元音字母 [^...]匹配不在括号内的字符 [^0-9]任意非数字字符 \w匹配字母/数字/下划线 \w+"Ab1", "word_" 等连续字符 \W匹配非字母/数字/下划线 \W"@", " ", "-" 等符号 \d匹配数字 \d{3}"123", "007" 等三位数字 \D匹配非数字 \D+"abc", "#$%" 等非数字串 \s匹配空白符(空格/Tab等) \s+连续的空白区域 \S匹配非空白符 \S"A", "1", "@" 等可见字符 -
重复限定符 --> 控制匹配次数
元字符 功能 示例 匹配结果说明 *0次或多次重复 ab*c"ac", "abc", "abbc" +1次或多次重复 ab+c"abc", "abbc" (排除"ac") ?0次或1次重复 colou?r"color" 或 "colour" {n}精确匹配n次 \d{4}四位数字如"2023" {n,}至少匹配n次 a{2,}"aa", "aaa" 等 {n,m}匹配n到m次 o{2,4}"oo", "ooo", "oooo" -
分组与捕获 --> 组合子表达式或捕获内容
元字符 功能 示例 匹配结果说明 (...)捕获分组 (ab)+"ab", "abab" (捕获为$1) (?:...)非捕获分组 `(?:ab)+ cd` 匹配"abab"或"cd"但不捕获 ` ` 逻辑或 `cat dog` "cat" 或 "dog" \1,\2...反向引用已捕获分组 (\w+)\s+\1匹配重复单词如"the the" -
特殊字符
元字符 功能 示例 匹配结果说明 `` 转义特殊字符 .匹配字面点号"." -字符范围(括号内生效) [a-z]任意小写字母 ^取反(括号内首位生效) [^A-Z]非大写字母字符
替换符
-
变量基本扩展(Variable Expansion)
功能:获取变量值并进行基础处理,是Shell脚本中最常用的扩展类型。
操作符 作用描述 示例 ${var}获取变量 var的值(基础形式,通常可省略大括号,如$var)name="Alice"; echo "Hello ${name}"→Hello Alice${var:-default}若 var未定义或为空,返回default;否则返回var的值(默认值替换)age=""; echo ${age:-18}→18(age为空,使用默认值18)${var:=default}若 var未定义或为空,将var赋值为default并返回;否则返回var的值unset score; echo ${score:=0}; echo $score→0(赋值并返回)${var:?error}若 var未定义或为空,输出error并终止脚本;否则返回var的值(错误检查)unset id; ${id:?id is required}→ 报错:-bash: id: id is required${var:+value}若 var已定义且非空,返回value;否则返回空(条件替换)status=ok; echo ${status:+success}→success(条件满足返回值)#!/usr/bin/env bash # read -p "input: " sss1 sss1=${sss1:-1} echo $sss1 <--- 不输入任何东西返回 sss1 read -p "input: " sss2 sss2=${sss2:=2} echo $sss2 <--- 不输入任何东西返回 sss2 read -p "input: " sss3 sss3=${sss3:?3} echo $sss3 <--- 不输入任何东西 异常退出脚本 read -p "input: " sss4 sss4=${sss4:+4} echo $sss4 <--- 不输入任何东西返回 sss4, 只能是数字才+1,字母也是4 -
字符串截取与替换(String Manipulation)
功能:对变量值进行截取、替换或删除部分内容,适用于处理路径、文件名等场景。
操作符 作用描述 示例 ${var:position}从 position(0开始)截取子串至末尾(正向截取)path="/home/user/file.txt"; echo ${path:5}→/user/file.txt(从第5位截取)${var:position:length}从 position截取长度为length的子串str="hello"; echo ${str:1:3}→ell(从第1位截取3个字符)${var/pattern/replace}替换第一个匹配 pattern的子串为replace(单次替换)text="apple banana apple"; echo ${text/apple/orange}→orange banana apple${var//pattern/replace}替换所有匹配 pattern的子串为replace(全局替换)text="apple banana apple"; echo ${text//apple/orange}→orange banana orange${var/#pattern/replace}仅替换开头匹配 pattern的子串为replace(前缀替换)str="hello world"; echo ${str/#hello/hi}→hi world(替换开头)${var/%pattern/replace}仅替换末尾匹配 pattern的子串为replace(后缀替换)str="hello world"; echo ${str/%world/there}→hello there(替换末尾) -
模式匹配与通配符
功能:通过通配符(
*、?、[]等)匹配符合规则的字符串,常用于文件名匹配或条件判断。通配符/操作 作用描述 示例 *匹配任意长度的任意字符(包括空字符) ls *.txt→ 列出当前目录所有.txt文件?匹配单个任意字符 ls file?.log→ 匹配file1.log、fileA.log(单个字符占位)[abc]匹配 a、b、c中的任意一个字符(字符集)ls [xy]*→ 匹配以x或y开头的文件[!abc]或[^abc]匹配除 a、b、c外的任意字符(取反字符集)ls [!0-9]*→ 匹配不以数字开头的文件{a,b,c}匹配 a、b、c中的任意一个字符串(大括号展开,非通配符,预先生成候选)echo {1,2,3}.txt→1.txt 2.txt 3.txt(生成多个字符串)[[ $var == pattern ]]在条件判断中使用通配符匹配变量值(需配合 [[ ]]关键字)name="test.txt"; if [[ $name == *.txt ]]; then echo "txt file"; fi→txt file(匹配成功) -
示例
]# he="hello world" ]# he2="hello world hello world" # ${#} 左边最短匹配模式 # 如果不加* 从顶头开始 ]# echo ${he#*o} # 结果为:world ]# echo ${he2#*o} # 结果为: world hello world # ${##} 左边最长匹配模式 ]# echo ${he##*o} # 结果: rld ]# echo ${he2##*o} # 结果: rld 匹配最左边最长的字符串 # ${%} 右边最短匹配模式 注意匹配 * 的位置 ]# echo ${he%o*} # 结果: hello w ]# echo ${he2%o*} # 结果: hello world hello w # ${%%} 右边最长匹配模式 ]# echo ${he%%o*} # 结果: hell ]# echo ${he2%%o*} # 结果: hell # ${/ /} 替换左起的第一个符合的字符串 ]# echo ${he2/world/xiong} 结果: hello xiong hello world # ${// /} 替换所有符合的字符串, 按最深度匹配 ]# echo ${he2//world/xiong} 结果: hello xiong hello xiong
运算符
-
逻辑运算符
符号 作用 && 或 -a 如果前值为true,则执行 或 -o 如果前值为false,则执行 !exp -
文件运算符
符号 作用 -e file 如果给定的文件存在,则条件测试的结果为真。 -(r w x) file 如果给定的文件存在,且是可( 读, 可写,可执行的) 则测试结果为真 -s file 如果给定的文件存在,且其大小大于0 -S file 文件存在且是套接字(socket) -f file 如果给定的文件存在,且是一个普通文件 -d file 如果给定的文件存在,且是一个目录 -L file 如果给定的文件存在,且是一个符号链接文件 -c file 如果给定的文件存在,且是字符特殊文件 -b file 如果给定的文件存在,且是块特殊文件 -p file 如果给定的文件存在,且是命名的管道文件 ]# cat test.sh #!/bin/bash # # 判断是否是套接字 [ -S '/run/docker.sock' ] && echo '是一个套接字' # 判断是否为目录,如果不存在则创建 [ -d './dir' ] && echo '是一个目录' || mkdir ./dir # 判断是否为文件,如果不存在则touch [ -f './file' ] && echo '是一个文件' || touch ./file # 判断是否为符号链接 [ -L './link' ] && echo "是一个软链接" -
字符串运算符
符号 作用 示例 = 检测两个字符串是否相等,相等返回 true。 [ b ] 返回 false != 检测两个字符串是否相等,不相等返回 true。 [ b ] 返回 true -z 检测字符串长度是否为0,为0返回 true。 [ -z $a ] 返回 false -n 检测字符串长度是否为0,不为0返回 true。 [ -n $a ] 返回 true str 检测字符串是否为空,不为空返回 true。 [ $a ] 返回 true =~ 正则表达式匹配运算符,用于匹配正则表达式的,配合[[]]使用 if [[ ! $file =~ check$ ]],用于判断 $file 是否是以 check 结尾]# cat test.sh #!/bin/bash # value1="xiong" value2="xion222" # 判断两个值是否相等, [ $value1 = $value2 ] && echo 'yep' || echo '不相等' # 获取docker的pid值,然后在获取docker.sock判断docker是否挂掉,如果都为空说明挂了 pid=`cat /run/docker.pid` # 判断pid是否为空, 如果为空为true [ -z '$pid' ] && echo '字符串为空' || echo '字符串有值 ' $pid # 使用-n会更好判断, 如果不为空为true [ -n '$pid' ] && echo $pid || echo '字符串为空' # 判断字符串是否为空,如果非空为true [ $value2 ] && echo '不为空' || echo '为空' -
关系运算符
符号 作用 示例 -eq 检测两个数是否相等,相等返回 true。 [ b ] 返回 true -ne 检测两个数是否相等,不相等返回 true。 [ b ] 返回 true -gt 检测左边的数是否大于右边的,如果是,则返回 true。 [ b ] 返回 false -lt 检测左边的数是否小于右边的,如果是,则返回 true。 [ b ] 返回 true -ge 检测左边的数是否大等于右边的,如果是,则返回 true。 [ b ] 返回 false -le 检测左边的数是否小于等于右边的,如果是,则返回 true。 [ b ] 返回 true [] 一对方括号,用于判断条件是否成立 [ b ],注意添加 4 个空格 [[]] 两对方括号是对[]的扩展,可使用<、>、&&、 等运算符 [[ b ]],只需要添加左右两边两个空格, 需要注意:使用==与!=时,仍需要4个空格 -
说明
-
运算符 [] 与 [[]] 的区别
实际上是 Bash 中 test 命令的简写,即所有的 [ expression ] 等于 test expression。而[[ expression ]]是 Bash 中真正的条件判断语句,其语法更符合编程习惯,建议使用。
-
Shell 中没有
<= 与 >=运算符,只能使用-le 与 -ge替代。
-
-
示例
num=100 num2=91 # 两值相等为true 不相等 [ $num -eq $num2 ] && echo '相等' || echo '不相等' # 两值不相等为true 不相等 [ $num -ne $num2 ] && echo '不相等' || echo '相等' # 左边大于右边为true num大于num2 [ $num -gt $num2 ] && echo 'num大于num2' || echo 'num小于num2' # 左边小于右边为true num大于num2 [ $num -lt $num2 ] && echo 'num小于num2' || echo 'num大于num2' # 左边大于等于右边为true num大于等于num2 [ $num -ge $num2 ] && echo 'num大于等于num2' || echo 'num小于等于num2' # 左边小于等于右边为true num大于等于num2 [ $num -le $num2 ] && echo 'num小于等于num2' || echo 'num大于等于num2'
-
数组
数组元素的下标由0 开始编号,获取数组中的元素要利用下标
-
定义数组
-
方式一:
array_name=(value1 value2 value3) -
方式二:
]# array_name[0]=value0 ]# array_name[1]=value1 ]# array_name[2]=value2
-
-
读取数组
符号 作用 ${value[index]} 取出数组的索引值, 从0开始 ${value[*]} 获取数组中所有的值 ${value[@]} 获取数组中所有的值 ${#value[@]} 获取当前数组有多少个值 ${#value[index]} 获取单个字符串长度,不加index就是0 ${value[*]::} ${数组名[@或*]:开始下标:结束下标} ${value[*]//} 数组值替换,不改变原字符串,${数组名[@或*]/模式/新值} -
示例
]# echo ${array_name[2]} # 结果: value2 ]# echo ${array_name[*]} # 结果: value0 value1 value2 ]# echo ${array_name[@]} # 结果: value0 value1 value2 ]# echo ${#array_name[*]} # 结果:3 ]# echo ${#array_name[1]} # 结果:6 ]# echo ${#array_name} # 结果: 6 默认下标为0 ]# echo ${array_name[@]:0:1} # 结果: value0 ]# echo ${array_name[@]:1} # 结果: value1 value2 ]# echo ${array_name[@]/value1/test} # 结果: value0 test value2 # 数组遍历打印 ]# for v in ${array_name[@]};do echo $v;done-
如果该下标元素已经存在,会怎么样?
答:会修改该下标的值为新的指定值。 例如:array_name[2]=100,数组被修改为(value0 value1 100) -
如果指定的下标已经超过当前数组的大小,如上述的arr_number的大小为2,指定下标为10或者11或者大于2的任意值会如何?
答:新赋的值被追加到数组的尾部。 例如:arr_number[13]=13,数组被修改为(value0 value1 value2 13) -
判断字符是否存在列表中
aaaa=[tcp,udp,TCP,UDP,Tcp,Udp] echo $aaa | grep -w "tcp1312323" >/dev/null && echo 111 || echo 222222 -
判断为数字
[root@localhost opt]# grep '^[[:digit:]]*$' <<< "123123a" && echo "number" || echo "not" not
-
-
-
删除操作
- 清除某个元素: unset arr_number[1],这里清除下标为1的数组;
- 清空整个数组: unset arr_number;
-
追加元组元素
因为shell 数组没有追加函数可以 利用数组的长度来追加元素 获取数组的长度:${#arr[*]} [root@localhost opt]# arr[0]=0 [root@localhost opt]# arr[1]=1 [root@localhost opt]# arr[2]=2 [root@localhost opt]# echo ${#arr[*]} 3 [root@localhost opt]# for a in ${arr[@]};do echo ${a};done [root@localhost opt]# for ((i=0;i<${#arr[@]};i++));do echo ${arr[i]};done -
示例
-
数组遍历
IAM_SFVWLI=(x1 x2 x3) xx=`(grep "^IAM_SFVWLI" x.conf | sed "s@^IAM_SFVWLI=((.*))@\1@")` # 获取数组元素字符串 xx="${IAM_SFVWLI[*]}" # 使用空格作为分隔符拆分字符串为数组 IFS=" " read -ra SERVERS <<< "$xx" # 遍历数组并处理元素 for server in "${SERVERS[@]}"; do echo "$server" done
-
数组数据处理
-
数组切片
${ARRAY[@]:offset:number} offset 要跳过的元素个数 number 要取出的元素个数 # 取偏移量之后的所有元素 ${ARRAY[@]:offset} ~]# xiong=(a b c d e f g) ~]# echo ${xiong[@]:1:2} b c ~]# echo ${xiong[@]:1} b c d e f g -
向数组中追加元素
ARRAY[${#ARRAY[*]}]=value ~]# xiong[${#xiong[1]}]=aaaa # 在第一个索引位置添加 ~]# echo ${xiong[@]} a aaaa c d e f g -
元组追加
[root@localhost ~]# xx=() [root@localhost ~]# xx+=(11 22 33) [root@localhost ~]# echo ${xx[@]} 11 22 33 [root@localhost ~]# xx+=(44 55) [root@localhost ~]# echo ${xx[@]} 11 22 33 44 55
字符串切片
-
定义默认值
${var: -length}: # 注意:冒号后必须有一空白字符 ~]# declare -i test # 定义空数组 ~]# echo ${test:-test} # 当数组为空时会显示默认值 test -
基于模式取子串
${var#*word}: 其中word可以是指定的任意字符 功能:自左而右,查找var变量所存储的字符串中,第一次出现的word, 删除字符串开头至第一次出现word字符串(含)之间的所有字符 ${var##*word}:同上,贪婪模式,不同的是,删除的是字符串开头至最后一次由word指定的字符之间的所有内容 示例 ~]# file="/var/log/message" ~]# echo ${file#*/} # var/log/message # 匹配第一个/ ~]# echo ${file##*/} # message # 贪婪模式 匹配最后的一个/ ${var%word*}:其中word可以是指定的任意字符 功能:自右而左,查找var变量所存储的字符串中,第一次出现的word, 删除字符串最后一个字符向左至第一次出现word字符串(含)之间的所有字符 ${var%%word*}: 同上,只不过删除字符串最右侧的字符向左至最后一次出现word字符之间的所有字符 ~]# echo ${file%/*} # /var/log ~]# echo ${file%%/*} # 空, /右边无字符串
算术运算
-
基础算术运算符
用于整数的加、减、乘、除、取余等基本运算。
运算符 含义 示例(使用 $((...))语法)+加法 echo $((2 + 3))结果为5-减法 echo $((10 - 4))结果为6*乘法(需转义或用 $((...)))echo $((5 * 6))结果为30/除法(整数除法,向下取整) echo $((10 / 3))结果为3%取余(模运算) echo $((10 % 3))结果为1 -
赋值运算符
用于将运算结果赋值给变量,结合基础运算符使用。
运算符 含义 示例 说明 =直接赋值 a=5将 5 赋值给变量 a+=加法赋值 a=5; a+=3(等价于a=$((a+3)))执行后 a的值为 8-=减法赋值 a=10; a-=4执行后 a的值为 6*=乘法赋值 a=2; a*=5执行后 a的值为 10/=除法赋值 a=10; a/=2执行后 a的值为 5 -
自增/自减运算符
运算符 含义 示例(前置) 示例(后置) 说明 ++自增 1 a=3; echo $((++a))→ 4a=3; echo $((a++))→ 3前置:先自增再返回值;后置:先返回值再自增 --自减 1 a=3; echo $((--a))→ 2a=3; echo $((a--))→ 3前置:先自减再返回值;后置:先返回值再自减 -
其它运算符
运算符 含义 示例 (()) 双小括号算术运算符,用于 替代expr 命令 for((i=0;i<10;++i))或者((out=$a*$b))或者if(($a==$b));then ... fi,无需添加空格了,更加符合 C 的编程语法, 逗号运算符 1、用在连接一连串的数学表达式中,这串数学表达式均被求值,但只有最后一个求值结果被返回。 2、用于参数替代中,表示首字母小写,如果是两个逗号,则表示全部小写,注意,这个特性在bash version 4的时候被添加的。
expr 算术运算
-
参数
运算类型 运算符 语法示例 结果 关键注意事项 加法 +expr 5 + 38 运算符两侧必须有空格 减法 -expr 10 - 46 同上 乘法 *expr 3 * 515 乘号需用反斜杠``转义 除法 /expr 15 / 35 仅支持整数除法,结果向下取整 取余 %expr 8 % 53 返回除法后的余数 -
示例
]# cat e1.sh #!/bin/bash # num1=100 num2=101 x=`expr $num1 + $num2` # 引用时注意左右空格 x1=`expr $num1 * $num2` # 如果是 乘法 需要先转义一下 x2=`expr $num1 - $num2` x3=`expr $num1 / $num2` x4=`expr $num1 % $num2` ]# expr 1 + 3 也需要注意左右空格, 计算时乘法需要先转义 # expr 1+3 会直接打印 1+3 # 判断是否为整形 expr "$1" : '[0-9]*$' >/dev/null && echo "整数" || echo "非整数" -
判断是否数字
expr $1 "+" 10 &>/dev/null [ $? -eq 0 ] && echo "数字" || echo "不是数字" -
(())使用方法
]# cat e2.sh #!/bin/bash # num1=100 num2=191 c1=$((num1+num2)) c2=$((num1-num2)) c3=$((num1*num2)) c4=$((num1/num2)) c5=$((num1%num2))
let 算术运算
let 命令取代并扩展了expr 命令的整数算术运, 如
num=100 num2=80
-
参数
运算符 说明 示例 输出结果 +加法 let a=2+3; echo $a5 -减法 let b=10-4; echo $b6 *乘法 let c=3*5; echo $c15 /除法(取整) let d=7/2; echo $d3 %取余 let e=10%3; echo $e1 **幂运算 let f=2**3; echo $f8 ++后自增 let x=5; let x++; echo $x6 --后自减 let y=5; let y--; echo $y4