shell元字符

引言

元字符
元字符指的是能够被shell解释的特殊字符,每个特殊字符都有其特殊含义,这些字符一方面可用于变量值的运算、我们可以称之为运算符,另外一方面可以和shell命令配合使用来达到更高级的效果。

一、算数运算,见上章节

二、测试运算

测试命令:test,详细可用man test查询

测试符号:[],注意只有一层中括号,中括号内左右两侧必须要有空格

test与[]效果都一样,参数也都一样
判断 /etc目录是否存在

2.1 测试文件状态

2.1.1 -d 目录

[root@manager scripts]# [ -d /etc/ ];echo $?  # 注意[]内左右两侧要有空格
0
[root@manager scripts]# test -d /etc/; echo $?
0

[root@manager scripts]#  test -f /etc/passwd;echo $?
0
[root@manager scripts]# [ -f /etc/passwd ];echo $?
0

2.1.2 -s 文件内容>0 非空等

[root@manager scripts]# touch a.txt
[root@manager scripts]# test -s a.txt;echo $? # 文件为空返回假
1
[root@manager scripts]# test -s /etc/hosts;echo $? # 文件非空返回真
0
[root@manager scripts]# [ -f /etc/passwd ];echo $?
0

2.1.3 -f 标准文件

[root@manager scripts]# test -f /etc/passwd;echo $?
0
[root@manager scripts]# test -f a.txt;echo $?
0

2.1.4 -w 可写

[tom@localhost ~]$ touch a.txt
[tom@localhost ~]$ chmod a-w a.txt
[tom@localhost ~]$ [ -w a.txt ];echo $?  # 返回假,注意,如果是root用户,无论如何都有写权限
1

2.1.5 -r 可读

2.1.5 -x 可执行

2.1.6 -L 符号连接

[tom@manager scripts]$ ll -d /bin
lrwxrwxrwx. 1 root root 7 Aug  2 18:18 /bin -> usr/bin
[tom@manager scripts]$ test -L /bin;echo $? 
0

2.1.7-u 文件有 suid 位设置

[root@manager ~]# ll /usr/bin/passwd
-rwsr-xr-x. 1 root root 27856 Apr  1  2020 /usr/bin/passwd
[root@manager ~]# [ -u `which passwd` ];echo $?
0
[root@manager ~]# [ -u `which cat` ]; echo $?
1

2.1.8 -c 判断是否为磁盘文件

[root@manager ~]# test -c /dev/tty;echo $?
0

2.2 测试字符串

2.2.1 == 两个字符串相等

[root@manager ~]# test "aaa"=="aaa";echo $?
0
[root@manager ~]# test "aaa" == "aaa";echo $?
0
[root@manager ~]# [ "bbb" == "bbb" ];echo  $?
0
[root@manager ~]# [ "bbb" == "b" ];echo  $?
1

2.2.2 != 两个字符串不相等

[root@manager ~]# [ "bbb" != "b" ];echo  $?
0
[root@manager ~]# test "a"!="b";echo $?
0

2.2.3 -z 字符串长度为零

[root@manager scripts]# ip=""
[root@manager scripts]# 
[root@manager scripts]# [ -z "$ip" ];echo $?  # 建议加引号
0
[root@manager scripts]# ip="172.16.1.7"
[root@manager scripts]# [ -z "$ip" ];echo $?
1


root@manager scripts]# ip=""
[root@manager scripts]# [ -n "$ip" ];echo $? # 注意要加引号
1
[root@manager scripts]# ip="172.16.1.7"
[root@manager scripts]# [ -n "$ip" ];echo $?
0

2.3 测试数值

man test
TRING1 = STRING2      # 判断字符串是否相等 
  the strings are equal

STRING1 != STRING2    # 字符串不相等
  the strings are not equal

INTEGER1 -eq INTEGER2   # 整数相等
  INTEGER1 is equal to INTEGER2

INTEGER1 -ge INTEGER2    # 大于等于
  INTEGER1 is greater than or equal to INTEGER2

INTEGER1 -gt INTEGER2  # 大于
  INTEGER1 is greater than INTEGER2

INTEGER1 -le INTEGER2  # 小于等于
  INTEGER1 is less than or equal to INTEGER2

INTEGER1 -lt INTEGER2   # 小于
  INTEGER1 is less than INTEGER2

INTEGER1 -ne INTEGER2   # 不等于
  INTEGER1 is not equal to INTEGER2
 总结 字符串判断用= !=,  数字判断用符号   


[root@localhost ~]# [ 10 -eq 10 ] && echo $?
0
[root@localhost ~]# [ 10 -eq 11 ] 
[root@localhost ~]# echo $?
1
[root@localhost ~]# 

[root@manager scripts]# [ $(id -u) -eq 0 ] && echo "当前是超级用户" || echo "you不是超级用户"
当前是超级用户

2.4 关系运算符

<

\>

<=

\>=

==

!=

&&

||

上述关系运算符需要配合(())使用(注意(())属于C语言风格的比较),最终都是用来当if判断或者while循环的条件



[root@localhost ~]# x=100

[root@localhost ~]# (($x>10))
[root@localhost ~]# echo $?
0

[root@localhost ~]# (($x < 10));echo $?
1

[root@localhost ~]# (($x == 100));echo $?
0

[root@localhost ~]# (($x != 100));echo $?
1

[root@localhost ~]# (($x != 100)) && (("localhost" == "localhost"))
[root@localhost ~]# echo $?
1

[root@localhost ~]# (($x != 100)) || (("localhost" == "localhost"))
[root@localhost ~]# echo $?
0

[root@localhost ~]# (($x != 100 && "localhost" == "localhost"));echo $?
1

[root@localhost ~]# (($x != 100 || "localhost" == "localhost"));echo $?
0


[root@manager scripts]# cat test.sh 
x=200
if (($x>10));then  # 接近或python的if风格 ,只要if 后表达式为真,则执行if内内容
	echo "123"
fi

注:字符运算使用-eq这种方式,选用的方式:[], 数字运算使用> < == ,选用的方式是:(())

2.5 [][[]]

[[]]与[]基本一样,不同的是[[]]支持正则匹配,不过要注意的是必须在内层中括号内左右两侧加空格

[root@manager scripts]# user="bert"
[root@manager scripts]# 
[root@manager scripts]# 
[root@manager scripts]# 
[root@manager scripts]# [[ "$user" == "bert" ]];echo $?; # 注意内层[]中包含的内容必须左右两侧加空格
0
[root@manager scripts]# [ "$user" == "bert" ];echo $?;
0
[root@manager scripts]# [ "$user" = "bert" ];echo $?; # 字符串比较一个等号也行两个等号也可以
0
[root@manager scripts]# [[ "$user" = "bert" ]];echo $?;
0

此外[[]]内部是可以使用正则的,注意:正则表达式不要加引号

[root@manager scripts]# [[ "$user" =~ "^bert$" ]];echo $?;
1
[root@manager scripts]# [[ "$user" =~ ^bert$ ]];echo $?;
0

[root@manager scripts]#  [[ ! "$USER" =~ t$ ]] && echo 此时不是管理员登录 || echo 是管理员登录
是管理员登录

2.5.1 判断是否是数字

[root@localhost ~]# num1=123
[root@localhost ~]# [[ "$num1" =~ ^[0-9]+$ ]];echo $?  # 判断是否是数字
0
[root@localhost ~]# [[ "$num1" =~ ^[0-9]+$ ]] && echo "是数字"
是数字



[root@localhost ~]# num2=abc123de
[root@localhost ~]# [[ "$num2" =~ ^[0-9]+$ ]];echo $?
1
[root@localhost ~]# [[ "$num2" =~ ^[0-9]+$ ]] || echo "num2不是数字"
num2不是数字

2.5.2 判断是否只含字母

[root@manager scripts]# string="hello"
[root@manager scripts]# 
[root@manager scripts]# [[ $string =~ ^[a-zA-Z]+$ ]] && echo "是字母"
是字母

2.5.3 传入两个数值信息, 自动让脚本显示数值比较情况

[root@manager scripts]# cat num.sh 
#!/bin/bash

[ $# -ne 2 ] && echo "输入错误,必须输入两个整数" && exit
[[ ! $1 =~ ^[0-9]+$ ]]  && [[ ! $2 =~ ^[0-9]+$ ]] && echo "两个参数必须是整数" && exit

[[ $1 -lt $2 ]] && echo "$1 < $2"

[[ $1 -eq $2 ]] && echo "$1 = $2"

[[ $1 -gt $2 ]] && echo "$1 > $2"

2.5.4 浮点数的对比

# 需要注意的是:bc的结果为1代表真,为0代表假
[root@localhost ~]# echo "10.3 >= 10.1" | bc
1
[root@localhost ~]# echo "10.3 != 10.1" | bc
1
[root@localhost ~]# echo "10.3 != 10.3" | bc
0

# 应用
[root@localhost ~]# x=10.3
[root@localhost ~]# y=10.1
[root@localhost ~]# [ `echo "$x >= $y" | bc` -eq 1 ] && echo "$x 大于 $y"
10.3 大于 10.1

2.5.5 总结

条件测试:

格式1: test 条件表达式
格式2[ 条件表达式 ]
格式3(()) 数值比较,运算  C语言
格式4[[ 条件表达式 ]],支持正则  =~


结合$符号
$[]	   # 整数运算
$(())  # 整数运算

$()    # 执行命令


其他
()     # 子shell中执行

三、 其他元字符

  1. `` 与$():取命令的结果
[root@localhost ~]# echo `pwd`
/root
[root@localhost ~]# echo $(pwd)
/root

不一样的地方在于$()可以嵌套,而``不能嵌套
[root@localhost ~]# echo $(ls $(pwd))

[root@manager tmp]# touch $(date +%F)_bak.tar.gz
[root@manager tmp]# ls
2021-09-25_bak.tar.gz


  1. ~家目录

  2. ... 当前目录与上级目录

  3. !调用历史命令、取反

# 1、调用历史命令
[root@manager tmp]# !658
ls
2021-09-25_bak.tar.gz
[root@manager tmp]# !cd   # 匹配最近的一次历史命令
cd /tmp/



# 2、取反1:对命令的结果取反
[root@manager tmp]# pwd
/tmp
[root@manager tmp]# echo $?
0

[root@manager tmp]# ! pwd
/tmp
[root@manager tmp]# echo $? # 对结果取反
1


# 3、取反2:效果与^雷同
[root@localhost ~]# touch /test/{1.txt,2.txt,a.txt,aaa_bbb.txt}
[root@localhost ~]# find /test ! -name 1.txt
/test
/test/2.txt
/test/a.txt
/test/aaa_bbb.txt

[root@localhost ~]# ls /test/[!0-9].txt  # .txt前只有一个字符,但是非数字
/test/a.txt
[root@localhost ~]# ls /test/[^0-9].txt  # .txt前只有一个字符,但是非数字
/test/a.txt

[root@aliyun test]# ls -a /etc/skel/.[!.]*
  1. @无特殊意义

  2. #注释

  3. $取变量值

[root@localhost ~]# x=1
[root@localhost ~]# echo $x
1
  1. %、-、+运算符,注意%可以与jobs配合“kill %工作号”杀后台进程。-减号还有区间及cd -回到上一级的意思
# 数学运算
# 1、bc是比较常用的linux计算工具了,而且支持浮点运算:
[root@localhost ~]# res=`echo 1+1 | bc`
[root@localhost ~]# echo $res
2

[root@localhost ~]# res=`echo 10 % 3 | bc`
[root@localhost ~]# echo $res
1

[root@localhost ~]# res=`echo 1.2+1.3|bc`
[root@localhost ~]# echo $res
2.5

[root@localhost ~]# res=`echo 5.0+3.0|bc`
[root@localhost ~]# echo $res
8.0

[root@localhost ~]# res=`echo "scale=2;5.0/3.0"|bc`
[root@localhost ~]# echo $res
1.66

[root@localhost ~]# res=`echo "scale=2;5.0/6.0"|bc`
[root@localhost ~]# echo $res
.83

# 2、expr不支持浮点数计算。而且要注意数字与运算符中的空格
[root@localhost ~]# res=`expr 5 / 3`  # 不支持浮点计算
[root@localhost ~]# echo $res
1

[root@localhost ~]# res=`expr 1+1`  # 注意:要有空格
[root@localhost ~]# echo $res
1+1
[root@localhost ~]# res=`expr 1 + 1`
[root@localhost ~]# echo $res
2

[root@localhost ~]# res=`expr 5 \* 3`  # 在expr中*号要转义才能用,否则报语法错误
[root@egon ~]# echo $res
15

# 3、$(()) 同expr,不支持浮点数运算
[root@localhost ~]# echo $((1+1))
2
[root@localhost ~]# echo $((1.0+2.0))
-bash: 1.0+2.0: 语法错误: 无效的算术运算符 (错误符号是 ".0+2.0"# 4、$[]同expr以及$(()),不支持浮点运算
[root@localhost ~]# x=1
[root@localhost ~]# echo $[$x+1]
2

# 5、let 不支持浮点数运算,而且不支持直接输出,只能赋值
[root@localhost ~]# let res=1+1
[root@localhost ~]# echo $res
2
[root@localhost ~]# 
[root@localhost ~]# let res=50/5
[root@localhost ~]# echo $res
10
[root@localhost ~]# let c=1.3*3
-bash: let: c=1.3*3: 语法错误: 无效的算术运算符 (错误符号是 ".3*3"
                
[root@aliyun test]# x=1
[root@aliyun test]# let x+=10
[root@aliyun test]# echo $x
11
  1. ^同!一样

  2. &后台运行

[root@localhost home]# echo "hello";sleep 3;echo "world" &
  1. *任意多个字符
[root@localhost ~]# touch 1.txt 2.txt aa.txt aaa.txt
[root@localhost ~]# rm -rf *.txt
[root@localhost ~]# touch 1.txt 2.txt aa.txt aaa.txt a1c.txt
[root@localhost ~]# ls *.txt
1.txt  2.txt  a1c.txt  aaa.txt  aa.txt
  1. ()在子shell中执行
[root@localhost ~]# (x=1)
[root@localhost ~]# echo $x

应用

[root@manager tmp]# (umask 066;touch a.txt) # umask的设置只在子shell中有效
[root@manager tmp]# ll a.txt 
-rw------- 1 root root 0 Sep 25 18:17 a.txt
[root@manager tmp]# 
[root@manager tmp]# touch b.txt
[root@manager tmp]# ll b.txt 
-rw-r--r-- 1 root root 0 Sep 25 18:18 b.txt

  1. _下划线:无特殊意义,可以用于名字的声明
[root@localhost ~]# tar -czvf  `date +%F_%H:%M:%S`_bak.tar.gz /etc/
  1. =赋值,==判断相等性
[root@localhost ~]# [ 1 == 1 ]  # 条件1 == 1的左右两边必须有空格
[root@localhost ~]# echo $?    # 判断上一条命令的结果是否为真,0=》true
0
  1. |管道:把一个进程的处理结果传递给另外一个进程
[root@localhost ~]# ps aux | grep python


|管道命令的作用,是将左侧命令的标准输出转换为标准输入,提供给右侧命令作为参数。
但是,大多数命令都不接受标准输入作为参数,只能直接在命令行输入参数,
这导致无法用管道命令传递参数。比如echo命令就不接受管道传参。
 [root@localhost ~]#   echo "hello world" | echo
 
xargs命令的作用,是将标准输入转为命令行参数,例如
$ echo "hello world" | xargs echo
hello world

[root@localhost ~]# find /home/ -type d -name "test*" |xargs ls
1.txt  2.txt  3.txt
[root@localhost ~]# ls /home/test
1.txt  2.txt  3.txt
  1. \转义特殊字符
[root@localhost ~]# mkdir a\ b.txt  # 虽然可以,但不推荐
[root@localhost ~]# ll
总用量 0
drwxr-xr-x. 2 root root 6 813 15:35 a b.txt
    

[root@localhost ~]# echo $RMB  # 默认会当成变量

[root@localhost ~]# echo '$RMB'  # 取消特殊意义
$RMB
[root@localhost ~]# echo \$RMB  # 取消特殊意义
$RMB
  1. []条件测试
[root@localhost ~]# name="bert"
[root@localhost ~]# [ $name == "bert" ];echo $?
0
[root@localhost ~]# name="adf"
[root@localhost ~]# [ $name == "bert" ];echo $?
1

[root@localhost ~]# [ -d /test ];echo $?
0

  1. 引号
''  强引用(在单引号中都视为普通字符)
" " 弱引用 (在双引号中保留变量)

[root@localhost ~]# x=111
[root@localhost ~]# echo "$x"
111
[root@localhost ~]# echo '$x'
$x

16 ;&&||连接多条命令


        
[root@localhost ~]# ls /test || mkdir /test  # 前一条命令执行不成功才会执行后续命令
0.txt  1.txt  2.txt  3.txt  4.txt  5.txt  6.txt  7.txt  8.txt  9.txt

[root@localhost ~]# ssdafsaf;ls # 不论前一条命令运行成功与否,都会执行后续命令
-bash: ssdafsaf: command not found
anaconda-ks.cfg


[root@localhost ~]# ssdafsaf && ls # 只有前一条命令执行成功,才会执行后续命令
-bash: ssdafsaf: command not found

  1. : 空命令,真值
[root@egon ~]# :
[root@egon ~]# echo $?
0


# 可以当做while 真的条件, 相当于while true
[root@localhost ~]# while :;do echo 1;sleep 1;done
1
1
1
1

  1. /路径分隔符

  2. {}循环列表

[root@localhost home]# touch /test/{0..9}.txt
[root@localhost home]# ls /test/
0.txt  1.txt  2.txt  3.txt  4.txt  5.txt  6.txt  7.txt  8.txt  9.txt

[root@localhost ~]# touch {1..3}{a..d}.txt
[root@localhost ~]# ls
1a.txt 1b.txt 1c.txt 1d.txt 2a.txt 2b.txt 2c.txt 2d.txt 3a.txt 3b.txt 3c.txt 3d.txt

[root@localhost ~]# x=100
[root@localhost ~ ]# echo ${x}%  # 控制变量名的范围
100%

[root@localhost ~]# echo $xrmb

[root@localhost ~]# echo ${x}rmb
100rmb

20。. 重定向

> >> 输出重定向
< << 输入重定向

> 覆盖  >> 追加
[root@localhost home]# cat >> a.txt << EOF
> 111
> 222
> 333
> EOF

0标准输入、1标准正确输出、2标准错误输出,&标准正确和错误输出
[root@localhost home]# pwd 1>a.txt
[root@localhost home]# cat a.txt 
/home
[root@localhost home]# gagag 2>a.txt
[root@localhost home]# cat a.txt 
bash: gagag: 未找到命令...
[root@localhost home]# gagaga &>/dev/null

< << 输入重定向
[root@localhost ~]# mysql -uroot -p123 < bbs.sql
[root@localhost home]# grep root < /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin

                        
[root@localhost home]# dd if=/dev/zero of=/a.txt bs=1M count=10
记录了10+0 的读入
记录了10+0 的写出
10485760字节(10 MB)已复制,0.024387 秒,430 MB/[root@localhost home]# dd </dev/zero >/b.txt bs=1M count=10
记录了10+0 的读入
记录了10+0 的写出
10485760字节(10 MB)已复制,0.0202365 秒,518 MB/[root@localhost home]# ll /a.txt 
-rw-r--r--. 1 root root 10485760 813 16:02 /a.txt
[root@localhost home]# ll /b.txt 
-rw-r--r--. 1 root root 10485760 813 16:03 /b.txt
  1. ?任意一个字符
[root@localhost ~]# ls ??.txt
aa.txt
[root@localhost ~]# ls a?c.txt
a1c.txt
[root@localhost ~]# rm -rf *.txt
  1. 范围中的任意一个字符[15] [ac] [a-z] [0-9]
[root@localhost ~]# touch a1c a2c axc aXc axd
[root@localhost ~]# ls a?c
a1c  a2c  axc  aXc
[root@localhost ~]# ls a[1x]c
a1c  axc
[root@localhost ~]# ls a[a-z]c # 不区分大小写
axc  aXc
[root@localhost ~]# ls a[A-Z]c  # 不区分大小写
axc  aXc
[root@localhost ~]# ls a[x]c
axc
[root@localhost ~]# ls a[X]c
aXc
[root@localhost ~]# ls a[0-9]c
a1c  a2c
[root@localhost ~]# ls /dev/sd[a-z]*
/dev/sda  /dev/sda1  /dev/sda2  /dev/sda3  /dev/sdb1

猜你喜欢

转载自blog.csdn.net/m0_46090675/article/details/120464160