一、通配符
1)通配符
通配符 | 描述 |
---|---|
* | 匹配任意字符串 |
? | 匹配任意单个字符 |
[…] | 匹配括号中的任意单个字符,使用-可以表示连续的字符;[ 后面使用!或^ 表示匹配不在括号中的所有其他内容;[] 中还支持POSIX标准字符类,如:[:alnum:]、等 |
案例一:
[root@localhost jiaofan]# ls fu?ctiom*
functiom-demo1.sh functiom-demo3.sh functiom-demo4.sh
[root@localhost jiaofan]# ls fu?ctiom-demo4.sh
functiom-demo4.sh
案例二:
[root@localhost jiaofan]# cat case-dome4.sh
#!/bin/bash
#功能描述:识别用户输入的字符类型,仅准确识别一个字符
read -p "请输入任意字符:" key
case $key in
[a-z])
echo "输入的是小写字母"
[A-Z])
echo "输入的是大写字母";;
[0-9])
echo "输入的是数字";;
*)
echo "输入的是其他特殊符号";;
esac
2)扩展通配符
扩展通配符 | 描述 |
---|---|
?(模式列表) | 匹配0次或1次指定的模式列表 |
+(模式列表) | 匹配1次或多次指定的模式列表 |
*(模式列表) | 匹配0次或多次指定的模式列表 |
@(模式列表) | 仅匹配1次指定的模式列表 |
!(模式列表) | 匹配指定模式列表之外的所有内容 |
[root@localhost jiaofan]# cat case-demo5.sh
#!/bin/bash
#演示扩展通配符的作用
shopt -s extglob
read -p "请输入任意字符:" key
case $key in
+([Yy]))
echo "输入了至少1个[Yy]";;
?([Nn])O)
echo "输入的是[Nn]O或仅为o";;
t*(o))
echo "输入的是t或too...";;
@([0-9]))
echo "输入的是单个数字";;
!([[:punct:]]))
echo "输入的不是标点符号";;
*)
echo "输入的是其他符号";;
esac
3)设置语言字符集
[root@localhost jiaofan]# localectl status #<==查看字符集
System Locale: LANG=zh_CN.UTF-8
VC Keymap: cn
X11 Layout: cn
[root@localhost jiaofan]# localectl list-locales | grep en #<==显示字符集列表
[root@localhost jiaofan]# localectl set-locale "LANG=zh_CN.UTF-8" #<==设置语言字符集
二、花括号
[root@localhost jiaofan]# echo {r,f,j} #<==对字符串扩展
r f j
[root@localhost jiaofan]# echo {hello,world} #<==对字符串扩展
hello world
[root@localhost jiaofan]# echo {a..z} #<==对字符串序列扩展
a b c d e f g h i j k l m n o p q r s t u v w x y z
[root@localhost jiaofan]# echo {a..z..2} #<==从a至z,步长为2
a c e g i k m o q s u w y
[root@localhost jiaofan]# echo {1..9..3} #<==从1至9,步长为3
1 4 7
[root@localhost jiaofan]# echo t{i,o}p
tip top
[root@localhost jiaofan]# echo t{0,e{a,m}}p
t0p teap temp
[root@localhost jiaofan]# cp aaa.txt{,.bak}
[root@localhost jiaofan]# ls aaa.txt*
aaa.txt aaa.txt.bak
[root@localhost jiaofan]#
三、波浪号
- ~表示家目录
- ~用户:表示用户家目录
- ~+:表示当前工作目录
- ~-:表示前一个工作目录
[root@localhost jiaofan]# echo ~ #<==输出家目录
/root
[root@localhost jiaofan]# echo ~/jiaofan/ #<==输出家目录下的jiaofan
/root/jiaofan/
[root@localhost jiaofan]# echo ~jiaofan #<==输出jiaofan的家目录
/home/jiaofan
[root@localhost jiaofan]# echo ~+ #<==输出当前路径
/root/jiaofan
[root@localhost jiaofan]# echo ~- #<==输出前一个工作路径
/root
[root@localhost jiaofan]# pwd
/root/jiaofan
四、变量替换:字符串切割与掐头去尾
1)变量引用
[root@localhost jiaofan]# name=jiaofan
[root@localhost jiaofan]# echo ${name}
jiaofan
2)变量测试
语法格式 | 功能描述 |
---|---|
${变量:-关键字} | 如果变量未定义或值为空,则返回关键字。否则,返回变量的值 |
${变量:=关键字} | 如果变量未定义或值为空,则将关键字赋值给变量,并返回结果。否则,直接返回变量的值 |
${变量:?关键字} | 如果变量未定义或值为空,则通过标椎错误显示包含关键字的错误信息。否则,直接返回变量的值 |
${变量:+关键字} | 如果变量未定义或值为空,就直接返回空。否则,返回关键字 |
[root@localhost jiaofan]# name=jiaofan
[root@localhost jiaofan]# echo ${name}
jiaofan
[root@localhost jiaofan]# echo ${name1} #<==设置两个变量name(有值)和name1(未定义值)
[root@localhost jiaofan]# echo ${name1:-dog} #<==未定义时输出关键字
dog
[root@localhost jiaofan]# echo ${name:-dog} #<==已定义,直接输出变量的值
jiaofan
[root@localhost jiaofan]# echo ${name1:=dog} #<==未定义时把关键字赋值给name1,并输出关键字
dog
[root@localhost jiaofan]# echo $name1 #<==再次查看name1时,已经有值了
dog
[root@localhost jiaofan]# echo ${name:=dog} #<==已定义,直接输出变量的值
jiaofan
[root@localhost jiaofan]# unset name1 #<==取消name1的变量
[root@localhost jiaofan]# echo ${name1:?dog} #<==未定义时标准错误输出,并显示关键字
-bash: name1: dog
[root@localhost jiaofan]# echo ${name:?dog} #<==已定义,直接输出变量的值
jiaofan
[root@localhost jiaofan]# echo ${name1:+dog} #<==未定义时返回空
[root@localhost jiaofan]# echo ${name:+dog} #<==已定义,返回关键字
dog
[root@localhost jiaofan]#
3)变量替换:字符串切割与掐头去尾
语法格式 | 功能描述 |
---|---|
${变量:开始位置} | 从变量的开始位置开始,切割截取变量的值到结尾。 |
${变量:开始位置:长度} | 从变量的开始位置开始,截取特定长度的变量值。 |
${变量#关键字} | 使用关键字对变量进行模式匹配,从左往右删除匹配到的内容,关键字可以使用*符号,使用#时为最短匹配(最短匹配掐头) |
${变量##关键字} | 使用关键字对变量进行模式匹配,从左往右删除匹配到的内容,关键字可以使用*符号,使用#时为最长匹配(最长匹配掐头) |
${变量%关键字} | 使用关键字对变量进行模式匹配,从右往左删除匹配到的内容,关键字可以使用*符号,使用#时为最短匹配(最短匹配去尾) |
${变量%%关键字} | 使用关键字对变量进行模式匹配,从右往左删除匹配到的内容,关键字可以使用*符号,使用#时为最短匹配(最短匹配去尾) |
案例一:切割字符串
[root@localhost jiaofan]# name="this is my world" #<==字符串排序从0开始,空格也算一位
[root@localhost jiaofan]# echo $name
this is my world
[root@localhost jiaofan]# echo ${name:3} #<==从3开始,截取到最后
s is my world
[root@localhost jiaofan]# echo ${name:3:3} #<==从3开始,截取三位
s i
案例二:掐头
[root@localhost jiaofan]# key="this is this is my world"
[root@localhost jiaofan]# echo ${key#is}
this is this is my world
[root@localhost jiaofan]# echo ${key#this} #<==掐头,去掉开始的字符串
is this is my world
[root@localhost jiaofan]# echo ${key#*is} #<==掐头,去掉开始的字符串到is结束
is this is my world
[root@localhost jiaofan]# echo ${key##*this} #<==最长匹配
is my world
案例三:去尾
[root@localhost jiaofan]# key="this is this is my world"
[root@localhost jiaofan]# echo ${key%is}
this is this is my world
[root@localhost jiaofan]# echo ${key%orld} #<==去尾,去到末尾指定字符串
this is this is my w
[root@localhost jiaofan]# echo ${key%is*}
this is this
[root@localhost jiaofan]# echo ${key%%is*} #<==最长匹配
th
[root@localhost jiaofan]#
4)变量内容的统计与替换
语法格式 | 功能描述 |
---|---|
${!前缀字符*} | 查找以指定字符串开头的变量名称,变量名之间使用IFS分隔 |
${!前缀字符@} | 查找以指定字符串开头的变量名称,@在引号中将被扩展为独立的单词 |
${!数组名称[*]} | 列出数组中所有下标,*在引号中会被扩展为一个整体 |
${!数组名称[@]} | 列出数组中所有下标,@在引号中会被扩展为独立的单词 |
${#变量} | 统计变量的长度,变量可以使数组 |
${变量/旧字符串/新字符串} | 将变量中的旧字符替换为新字符串,仅替换第一个 |
${变量//旧字符串/新字符串} | 将变量中的旧字符替换为新字符串,替换所有 |
${变量^匹配字符} | 将变量中的小写替换为大写,仅替换第一个 |
${变量^^匹配字符} | 将变量中的小写替换为大写,替换所有 |
${#量,匹配字符} | 将变量中的大写替换为小写,仅替换第一个 |
${变量,匹配字符} | 将变量中的大写替换为小写,替换所有 |
1)案例一:
[root@localhost jiaofan]# echo ${!U*} #<==列出以U开头的所有变量名
UID USER
[root@localhost jiaofan]# echo ${!U@} #<==列出以U开头的所有变量名
UID USER
2)*和@的区别
使用*提取数组中的所有元素时,会把所有元素视为一个整体,而使用@则将数组所有元素视为若干个体。
[root@localhost jiaofan]# bash arrry.sh
1-"a b c d e f" #<==用到*时,abcdef是一个整体,所以循环一次就结束
[root@localhost jiaofan]# cat arrry.sh
#!/bin/bash
name=(a b c d e f)
for i in "${name[*]}"
do
let y++
echo $y-\"$i\"
done
[root@localhost jiaofan]# bash arrry.sh #<==用到@时,abcdef以IFS的空格为分隔符,所以循环多次才结束
1-"a"
2-"b"
3-"c"
4-"d"
5-"e"
6-"f"
[root@localhost jiaofan]# cat arrry.sh
#!/bin/bash
name=(a b c d e f)
for i in "${name[@]}"
do
let y++
echo $y-\"$i\"
done
3)案例二:字符替换
[root@localhost jiaofan]# key="this is this is my world"
[root@localhost jiaofan]# echo ${key/my/me}
this is this is me world
[root@localhost jiaofan]# echo ${key//is/are}
thare are thare are my world
4)大小写替换
[root@localhost jiaofan]# echo $key
this is this is my world
[root@localhost jiaofan]# echo ${key^t} #<==将第一个t变为大写
This is this is my world
[root@localhost jiaofan]# echo ${key^^t} #<==将所有t变为大写
This is This is my world
[root@localhost jiaofan]# echo ${key^^[is]} #<==将所有is变为大写
thIS IS thIS IS my world
[root@localhost jiaofan]# echo ${key^[is]} #<==失败,按理说第一个is变为大写
this is this is my world
[root@localhost jiaofan]# echo ${key^i} #<==失败,按理说第一个i变为大写
this is this is my world
[root@localhost jiaofan]# echo ${key^} #<==将首字母变为大写
This is this is my world
[root@localhost jiaofan]# key=${key^^} #<==将所有字母替换为大写
[root@localhost jiaofan]# echo $key
THIS IS THIS IS MY WORLD
[root@localhost jiaofan]# echo $key
THIS IS THIS IS MY WORLD
[root@localhost jiaofan]# echo ${key,} #<==将首字母变为小写
tHIS IS THIS IS MY WORLD
[root@localhost jiaofan]# echo ${key,,} #<==将所有字母替换为小写
this is this is my world
[root@localhost jiaofan]# echo ${key,H} #<==按道理说可以将第一个H变为小写
THIS IS THIS IS MY WORLD
[root@localhost jiaofan]# echo ${key,,H} #<==所有H变为小写
ThIS IS ThIS IS MY WORLD
[root@localhost jiaofan]# echo ${key,,[IS]} #<==is变为小写
THis is THis is MY WORLD
[root@localhost jiaofan]#
五、命令替换
- $()
- ``反引号
[root@localhost ~]# echo -e "systemctl CPU load:\n$(date +%Y-%m-%d;uptime)"
systemctl CPU load:
2022-02-18
10:38:59 up 2 min, 1 user, load average: 0.06, 0.06, 0.03
[root@localhost ~]# echo -e "systemctl CPU load:\n`date +%Y-%m-%d;uptime`"
systemctl CPU load:
2022-02-18
10:39:13 up 2 min, 1 user, load average: 0.05, 0.06, 0.03
[root@localhost ~]#
六、进程替换
命令替换是将一个命令输出结果返回并且赋值给变量,而进程替换则将进程的返回结果通过命名管道的方式传递给另一个进程。
进程替换的格式:<(命令)或者>(命令)。一旦使用了进程替换功能,系统将会在/dev/fd/目录下创建文件描述符文件,通过该文件描述符将进程的输出结果传递给其他进程。
[root@localhost ~]# who | wc -l
1
[root@localhost ~]# wc -l <(who)
1 /dev/fd/63
[root@localhost ~]# ls /dev/fd/63
ls: 无法访问/dev/fd/63: 没有那个文件或目录
1、|可以将who的输出结果通过匿名管道传递给wc。
2、<(who) 可以把who的结果保存到/dev/fd/63这个文件描述符中,该文件描述符作为wc -l 命令的输入参数。
3、文件描述符实际上是动态生成的,所以当进程执行完毕,在使用ls查看该文件描述符时会提示没有改文件。
案例一:多进程的输出结果传递给一个进程作为其输入参数。下面我们要提取/etc/passwd 文件中的账户名称(第一列)和家目录(第六列)。在提取/etc/shadow 中的密码信息(第二列),最后通过paste的命令合并为一个文件信息。
[root@localhost ~]# paste <(cut -d: -f1,6 /etc/passwd) <(cut -d: -f2 /etc/shadow)
root:/root $6$XgNSiECUP64BqMp7$.iouHxqaSzzcUFGXJOUwAMm6v/u1R.3utgLJqt/QAnwRrLX3DxTy8vDzy/oCrBdqX8lWXnFfTKxVnTqR4HhAz.
bin:/bin *
daemon:/sbin *
adm:/var/adm *
lp:/var/spool/lpd *
... ...
案例二:tee覆盖原有文件的内容。把ls的结果过滤保存到两个文件中,并在屏幕显示
[root@localhost ~]# ls | tee >(grep tst$ > tst.log) >(grep conf$ > conf.log)
a.conf
a.tst
b.conf
b.tst
c.conf
c.tst
[root@localhost ~]# cat tst.log
a.tst
b.tst
c.tst
[root@localhost ~]# cat conf.log
a.conf
b.conf
c.conf
[root@localhost ~]#
七、路径替换
[root@localhost jiaofan]# basename b.sh #<==获取文件名
b.sh
[root@localhost jiaofan]# dirname b.sh #<==获取文件的路径,删除文件名
.
[root@localhost jiaofan]# basename /etc/hosts
hosts
[root@localhost jiaofan]# dirname /etc/hosts
/etc
[root@localhost jiaofan]#
八、单词切割
在Shell 中使用内部变量IFS (Internal Field Seprator)来决定项目列表或值列表的分隔符,IFS 的默认值为空格、Tab 制表符或换行符。使用 for 循环读取项目列表或值列表时,就会根据IFS 的值判断列表中值的个数,最终决定循环的次数。
特殊的控制字符,可以设置分隔符为特殊控制字符。
控制字符 | 描述 |
---|---|
\a | Bell响铃符 |
\b | Backspace退格符 |
\f | Form Feed 换行符,光标仍旧停留在原来的位置 |
\n | New Line 换行符,且光标移至行首 |
\r | Return 光标移至行首,但不换行 |
\t | Horizontal Tab 水平制表符 |
\v | Vertical Tab 垂直制表符 |
\nnn | 任意八进制字符 |
案例一:输出查看$IFS
[root@localhost ~]# echo $IFS #<==因为IFS的值是空格或Tab制表符,所以无法显示内容,另外IFS的值还是换行符,所以有空行
[root@localhost ~]# printf "%s" $IFS #<==printf 也无内容
[root@localhost ~]# printf "%s" "$IFS" | od -b #<==转换成八进制看看,040是空格键、011是Tab制表符、012是换行符。
0000000 040 011 012
案例二:修改IFS
[root@localhost ~]# OLD_IFS="$IFS" #<==备份原来的,也可以自己设置默认值
[root@localhost ~]# IFS=";" #<==设置分隔符为“;”
[root@localhost ~]# read -p "请输入3个数字:" x y z #<==以空格为分隔符测试
请输入3个数字:a b c
[root@localhost ~]# echo $x
a b c #<==abc三个值都分给你x
[root@localhost ~]# echo $y $z
[root@localhost ~]# read -p "请输入3个数字:" x y z #<==以分号为分隔符测试
请输入3个数字:a;b;c
[root@localhost ~]# echo $x #<==成功
a
[root@localhost ~]# echo $y
b
[root@localhost ~]# echo $z
c
[root@localhost ~]# IFS="$OLD_IFS" #<==恢复之前的值。
案例三:设置IFS为特殊控制字符
错误设置
[root@localhost ~]# IFS="\t" #错误设置,实际这是以字母t为分隔符
[root@localhost ~]# read -p "请输入3个数字:" x y z
请输入3个数字:a b c #<==中间是Tab键进行分隔的
[root@localhost ~]# echo $x #<==测试结果是设置错误
a b c
[root@localhost ~]# echo $y $z
[root@localhost ~]# read -p "请输入3个数字:" x y z #<==测试是不是以t为分隔符
请输入3个数字:atbtc
[root@localhost ~]# echo $x
a
[root@localhost ~]# echo $y
b
[root@localhost ~]# echo $z
c
正确设置:$‘string’ 必须是单引号
[root@localhost ~]# IFS=$"\t" #<==双引号设置出现错误
[root@localhost ~]# read -p "请输入3个数字:" x y z
请输入3个数字:a b c
[root@localhost ~]# echo $x
a b c
[root@localhost ~]# IFS=$'\t' #<==单引号设置成功
[root@localhost ~]# read -p "请输入3个数字:" x y z
请输入3个数字:a b c
[root@localhost ~]# echo $x
a
[root@localhost ~]# echo $y
b
[root@localhost ~]# echo $z
c
[root@localhost ~]# IFS=$' \t\n' #<==恢复默认设置:空格、Tab制表符或换行符。