专业编程基础技术教程

网站首页 > 基础教程 正文

Shell编程基础(二)变量与正则表达式

ccvgpt 2025-02-15 14:46:25 基础教程 28 ℃

Shell中引号的使用

Shell中支持的引号:””(双引号)、’’(单引号)、··(反引号)

单引号与双引号

作用:将字符串作为一个整体。

Shell编程基础(二)变量与正则表达式

如我们创建文件时:

#不使用引号时,将创建3个文件
[root@localhost test]# touch a b c
[root@localhost test]# ls -l
total 0
-rw-r--r-- 1 root root 0 Aug 31 09:57 a
-rw-r--r-- 1 root root 0 Aug 31 09:57 b
-rw-r--r-- 1 root root 0 Aug 31 09:57 c
#使用引号则将a b c作为一个文件的文件名
[root@localhost test]# touch "a b c"
[root@localhost test]# ls -l
total 0
-rw-r--r-- 1 root root 0 Aug 31 09:57 a
-rw-r--r-- 1 root root 0 Aug 31 09:57 a b c
-rw-r--r-- 1 root root 0 Aug 31 09:57 b
-rw-r--r-- 1 root root 0 Aug 31 09:57 c

双引号与单引号的区别:

单引号可以屏蔽特殊符号,将特殊符号的特殊含义屏蔽,转化为字符表面的含义,不能解析变量。

# ‘#’号在Shell中为单行注释的标志,直接echo输出则#及后面的内容不会被执行
[root@localhost test]# echo #lsk
[root@localhost test]# echo "#ls"
#ls
[root@localhost test]# echo '#ls'
#ls
# 定义变量,直接echo输出及使用双引号,变量将被解析,使用单引号不能解析
[root@localhost test]# test="Hello World"
[root@localhost test]# echo $test
Hello World
[root@localhost test]# echo "$test"
Hello World
[root@localhost test]# echo '$test'
$test
# 使用\将$符进行转义,$转移为普通字符
[root@localhost test]# echo "\$test"
$test
[root@localhost test]# echo \$test
$test

反引号

反引号是一个命令替换符号,它可以使用命令的输出结果替代命令。

# 使用反引号将date命令的输出结果作为备份文件名的一部分
[root@localhost test]# tar -zcf log-`date +"%Y-%d-%m"`.tar.gz /var/log/
[root@localhost test]# ls
a a b c b c log-2021-31-08.tar.gz
# 使用反引号将统计登录系统账户数作为值赋给变量
[root@localhost test]# userTotal=`who | wc -l`
[root@localhost test]# echo $userTotal
2

$()组合符号与反引号的功能相同

[root@localhost test]# echo "当前系统账户登录数量为:$(who | wc -l)"
当前系统账户登录数量为:2
[root@localhost test]# echo "当前系统账户登录数量为:$(who | wc -l)"
当前系统账户登录数量为:2
[root@localhost test]# ping -c2 $(hostname)
PING localhost (127.0.0.1) 56(84) bytes of data.
64 bytes from localhost (127.0.0.1): icmp_seq=1 ttl=64 time=0.015 ms
64 bytes from localhost (127.0.0.1): icmp_seq=2 ttl=64 time=0.039 ms
--- localhost ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1002ms
rtt min/avg/max/mdev = 0.015/0.027/0.039/0.012 ms

Shell变量

Shell中变量的类型有:

  1. 自定义变量:用户自主设置的变量
  2. 环境变量:变量名通常大写,有操作系统维护
  3. 位置变量:bash内置变量,存储脚本执行时的参数
  4. 预定义变量:bash内置变量,可以调用但是不能修改

自定义变量

用户自定义变量时,变量名的规则:变量名仅可以使用字母数字下划线组合,但是不能以数字开头。在实际定义时最好使用比较容易理解的单词或拼音,切记不要使用随意的字符作为变量名,没有规律的变量名会让脚本的可阅读性变得极差。

定义变量格式:变量名=变量值

取消变量:unset 变量名

注意:=号两边不能有空格,不要使用关键字作为变量名,如:ls、cd等

# 定义变量时=号两边有空格时将报错
[root@localhost test]# var ="value"
-bash: var: command not found
[root@localhost test]# var= "value"
-bash: value: command not found
[root@localhost test]# var = "value"
-bash: var: command not found
# 自定义变量
[root@localhost test]# var="value"
# 输出变量
[root@localhost test]# echo $var
value
# 取消变量
[root@localhost test]# unset var
[root@localhost test]# echo $var
[root@localhost test]#

当输出变量时,变量名后面直接跟其他字母、数字或下划线时,需要使用{}将变量名括起来。

[root@localhost test]# money=999
[root@localhost test]# echo $money
999
#变量名后直接跟字母将无任何输出,moneyRMB将作为整个变量名,未定义
[root@localhost test]# echo $moneyRMB
# 使用{}分隔变量名及其他字符
[root@localhost test]# echo ${money}RMB
999RMB
[root@localhost test]# echo $money_RMB
[root@localhost test]# echo $money12RMB
[root@localhost test]# echo ${money}12RMB
99912RMB
[root@localhost test]# echo ${money}_RMB
999_RMB
[root@localhost test]# echo $money:RMB
999:RMB
[root@localhost test]# echo $money-RMB
999-RMB

环境变量

环境变量一般存储在/etc/profile或~/.bash_profile中,可以使用命令env查看所有环境变量。

常用的环境变量有:

  1. PATH:系统环境变量路径
  2. PWD:用户当前工作目录
  3. USER:当前登录系统的用户名
  4. UID:当前账号的UID
  5. HOME:当前用户的家目录
  6. SHELL:当前用户的SHEEL解释器
  7. RANDOM:返回0~32767之间的随机整数

位置变量

位置变量是存储脚本执行时的参数,使用$n表示,n为整数序列,n大于9是整数需使用{}号分隔,如:$1、$2...${11}、${12}...

[root@localhost test]# vim test.sh
#!/bin/bash
# 接收并输出位置变量
echo $1
echo $2
echo $2
[root@localhost test]# chmod +x test.sh
[root@localhost test]# ./test.sh 11 22 33
11
22
22

预定义变量

预定义变量用来保存脚本程序的执行信息。可以直接使用,但是不能修改及赋值。

常见的预定义变量表:

变量名

描述

$0

返回当前命令的名称

$#

返回命令参数的个数

$*

返回命令行的所有参数,“$*”所有参数作为一个整体

$@

返回命令行的所有参数,“$@”所有参数作为独立的个体

$?

返回上一条命令退出时的状态码(一般0表示执行成功,非0表示执行失败)

$$

返回当前进程的进程号

$!

返回最后一个后台进程的进程号

[root@localhost test]# vim sys_var.sh
#!/bin/bash
echo "当前脚本的名称为:"$0
echo "当前脚本的第1个参数为:"$1
echo "当前脚本的第2个参数为:"$2
echo "当前脚本的第3个参数为:"$3
echo "当前脚本的所有参数为:"$*
echo "创建一个文件..."
# 所有参数将作为一个整体,创建一个以所有参数为名称的文件
touch "$*"
echo "创建多个文件..."
# 所有参数作为独立的个体,创建以每个参数为名称的多个文件
touch "$@"
ls /etc/passwd
echo "执行成功的返回状态码:$?"
ls /abcd
echo "执行失败的返回状态码:$?"
echo "当前进程的进程号:"$$
echo "最后一个后台进程的进程号:"$!
[root@localhost test]# bash sys_var.sh A B C D 3
当前脚本的名称为:sys_var.sh
当前脚本的第1个参数为:A
当前脚本的第2个参数为:B
当前脚本的第3个参数为:C
当前脚本的所有参数为:A B C D 3
创建一个文件...
创建多个文件...
/etc/passwd
执行成功的返回状态码:0
ls: cannot access /abcd: No such file or directory
执行失败的返回状态码:2
当前进程的进程号:3701
最后一个后台进程的进程号:
[root@localhost test]# ll
total 536
-rw-r--r-- 1 root root 0 Aug 31 11:18 3
-rw-r--r-- 1 root root 0 Aug 31 09:57 a
-rw-r--r-- 1 root root 0 Aug 31 11:18 A
-rw-r--r-- 1 root root 0 Aug 31 09:57 a b c
-rw-r--r-- 1 root root 0 Aug 31 11:18 A B C D 3
-rw-r--r-- 1 root root 0 Aug 31 09:57 b
-rw-r--r-- 1 root root 0 Aug 31 11:18 B
-rw-r--r-- 1 root root 0 Aug 31 09:57 c
-rw-r--r-- 1 root root 0 Aug 31 11:18 C
-rw-r--r-- 1 root root 0 Aug 31 11:18 D
-rw-r--r-- 1 root root 540239 Aug 31 10:15 log-2021-31-08.tar.gz
-rw-r--r-- 1 root root 503 Aug 31 11:17 sys_var.sh
-rwxr-xr-x 1 root root 67 Aug 31 11:01 test.sh

变量的作用范围

局部变量

只在当前Shell环境中有效,无法在子shell环境中使用。

# 当前Shell中定义变量var,只在当前shell环境中有效
[root@localhost test]# var="test"
[root@localhost test]# echo $var
test
# 进入子shell环境中,变量无法使用
[root@localhost test]# sh
sh-4.2# echo $var
sh-4.2# exit
exit
[root@localhost test]# echo $var
test

全局变量

在当前Shell及子shell中均有效。

使用export定义全局变量

[root@localhost test]# export var="test1"
[root@localhost test]# echo $var
test1
[root@localhost test]# sh
sh-4.2# echo $var
test1
sh-4.2# sh
sh-4.2# echo $var
test1
sh-4.2# exit
exit
sh-4.2# echo $var
test1
sh-4.2# exit
exit
[root@localhost test]# echo $var
test1

数据过滤与正则表达式

数据过滤

grep命令

grep命令可以查找关键词并打印匹配的行。

语法格式:

grep [选项] 匹配模式 [文件]

常用命令选项:

  1. -i:不区分字母带小写
  2. -v:取反匹配
  3. -w:匹配单词
  4. -q:静默匹配,不将结果显示在屏幕上
  5. -E:使用扩展正则匹配
  6. -P:使用Perl兼容正则匹配
[root@localhost test]# vim test.txt
Hello The World!
Other men live to eat, while I eat to live.
It is never too late to mend.
[root@localhost test]# grep The test.txt
Hello The World!
[root@localhost test]# grep the test.txt
Other men live to eat, while I eat to live.
[root@localhost test]# grep -i the test.txt
Hello The World!
Other men live to eat, while I eat to live.
[root@localhost test]# grep -vi the test.txt
It is never too late to mend.
[root@localhost test]# grep -wi the test.txt
Hello The World!
[root@localhost test]# grep -qi the test.txt

egrep命令

使用扩展正则匹配过滤数据

# 匹配0出现至少2次,最多3次的行
[root@localhost test]# egrep "0{2,3}" passwd
games:x:12:100:games:/usr/games:/sbin/nologin

正则表达式

基本正则表达式(Basic Regular Expression)

基本正则符号及含义:

正则符号

含义

c

匹配字母c

.

匹配任意单个字符

*

匹配前一个字符出现0次或多次

.*

匹配多个任意字符

[集合]

匹配集合中的任意单个字符

[^集合]

对集合取反

^

匹配字符串的开头

$

匹配字符串的结尾

\

匹配转义后的字符

\{m,n\}

匹配前一个字符m到n次

\{m,\}

匹配前一个字符至少m次

\{m\}

匹配前一个字符重复m次

# 拷贝passwd文件到当前目录
[root@localhost test]# cp /etc/passwd ./
# 查找有root的行
[root@localhost test]# grep root passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
# 查找:与0:之间有两个任意字符的行
[root@localhost test]# grep ":..0:" passwd
root:x:0:0:root:/root:/bin/bash
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
...
# 查找至少有一个0的行
[root@localhost test]# grep "00*" passwd
root:x:0:0:root:/root:/bin/bash
sync:x:5:0:sync:/sbin:/bin/sync
...
# 查找包含oot或ost的行
[root@localhost test]# grep "o[os]t" passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
# 查找包含数字的行
[root@localhost test]# grep "[0-9]" passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
...
# 查找包含f-q小写字母的行
[root@localhost test]# grep "[f-q]" passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
...
# 查找以root开头的行
[root@localhost test]# grep "^root" passwd
root:x:0:0:root:/root:/bin/bash
# 查找以bash结尾的行
[root@localhost test]# grep "bash$" passwd
root:x:0:0:root:/root:/bin/bash
test:x:1001:1001::/home/test:/bin/bash
# 查找sbin后面不是n的行
[root@localhost test]# grep "sbin[^n]" passwd
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
...
# 查找数字0出现至少一次,最多2次的行
[root@localhost test]# grep "0\{1,2\}" passwd
root:x:0:0:root:/root:/bin/bash
sync:x:5:0:sync:/sbin:/bin/sync
...
# 查找两个root之间可以是任意字符的行
[root@localhost test]# grep "\(root\).*\1" passwd
root:x:0:0:root:/root:/bin/bash
# 查找空白行
[root@localhost test]# grep "^$" passwd
# 查找非空白行
[root@localhost test]# grep -v "^$" passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin

扩展正则表达式(Extended Regular Expression)

扩展正则表达式及其含义

正则符号

含义

{m,n}

等同于基本正则的\{m,n\}

+

匹配前面的字符出现一次或多次

?

匹配前面的字符出现0次或1次

|

匹配逻辑或

()

匹配正字集合,同时也有保留的意思

{m,}

等同于基本正则的\{m,\}

{m}

等同于基本正则的\{m\}

grep 使用扩展正则需要使用-E选项

[root@localhost test]# grep -E "0{2,3}" passwd
games:x:12:100:games:/usr/games:/sbin/nologin
[root@localhost test]# grep -E "root|test" passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
test:x:1001:1001::/home/test:/bin/bash

POSIX规范的正则表达式

POSIX正则表达式规范可以帮助我们解决语系的问题,并且POSIX规范的正则表达式也比较接近于自然语言。

POSIX规范字符集

字符集

含义

字符集

含义

[:alpha:]

字母字符

[:graph:]

非空格字符

[:alnum:]

字母与数字字符

[:print:]

任意可以显示的字符

[:cntrl:]

控制字符

[:space:]

任意可以产生空白的字符

[:digit:]

数字字符

[:blank:]

空格与Tab键字符

[:xdigit:]

十六进制数字字符

[:lower:]

小写字符

[:punct:]

标点符号

[:upper:]

大写字符

root@localhost test]# grep "[[:punct:]]" passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
[root@localhost test]# grep "[[:alnum:]]" passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin

Perl兼容正则表达式

Perl兼容的正则符号

符号

含义

\b

匹配单词边界

\B

和\b相反

\w

匹配字母数字下划线

\W

和\w相反

\s

匹配空白

\d

匹配数字

\D

匹配非数字

grep使用Perl兼容的正则表达式过滤数据,需要使用-P选项

[root@localhost test]# grep "sh" passwd
root:x:0:0:root:/root:/bin/bash
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
wangyh:x:1000:1000::/home/wangyh:/bin/bash
test:x:1001:1001::/home/test:/bin/bash
[root@localhost test]# grep -P "sh\b" passwd
root:x:0:0:root:/root:/bin/bash
wangyh:x:1000:1000::/home/wangyh:/bin/bash
test:x:1001:1001::/home/test:/bin/bash
[root@localhost test]# grep -P "\w" passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
[root@localhost test]# grep -P "\W" passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin

算术运算

整数运算

语法格式:

  1. $((表达式))
  2. $[表达式]
  3. let 表达式

注:上述命令无法执行小数的运算

常用的运算符号

运算符号

含义描述

++

自加1

--

自减1

+、-、*、/

加、减、乘、除

**

求幂

%

取余

+=

自加任意数

-=

自减任意数

*=

自乘任意数

/=

自除任意数

%=

对任意数取余

&&

逻辑与

||

逻辑或

>

大于

<

小于

>=

大于等于

<=

小于等于

表达式1?表达式2:表达式3

若表达式1成立则执行表达式2,否则执行表达式3

[root@localhost test]# echo $((8+3))
11
[root@localhost test]# echo $((8-3))
5
[root@localhost test]# echo $((8*3))
24
[root@localhost test]# echo $((8/3))
2
[root@localhost test]# echo $((8%3))
2
[root@localhost test]# echo $((8**3))
512
[root@localhost test]# i=1
[root@localhost test]# echo $((i++))
1
[root@localhost test]# echo $i
2
[root@localhost test]# echo $((++i))
3
[root@localhost test]# echo $i
3
[root@localhost test]# echo $((i--))
3
[root@localhost test]# echo $i
2
[root@localhost test]# echo $((--i))
1
[root@localhost test]# echo $i
1
[root@localhost test]# echo $[i+=5]
6
[root@localhost test]# echo $[i-=2]
4
[root@localhost test]# echo $[i*=3]
12
[root@localhost test]# echo $[i/=4]
3
[root@localhost test]# echo $[i%=2]
1
[root@localhost test]# echo $[i**=2]
[root@localhost test]# echo $[3>2 && 3> 1]
1
[root@localhost test]# echo $[3>2 && 3> 4]
0
[root@localhost test]# echo $[3>2 || 3> 4]
1
[root@localhost test]# echo $[3>5 || 3> 4]
0
[root@localhost test]# x=2;y=3
[root@localhost test]# echo $[x > 3 ? x : y]
3
[root@localhost test]# echo $[x < 3 ? x : y]
2

使用let命令计算时,默认不会输出计算的结果,一般需要将运算的结果赋值给变量,通过变量查看运算的结果。另外使用let运算时,不需要在变量名前加$符号。

[root@localhost test]# x=5;y=8
[root@localhost test]# let z=x+y
[root@localhost test]# echo $z
13
[root@localhost test]# let m=x*y
[root@localhost test]# echo $m
40

bc命令

bc命令支持交互式和非交互式两种方式。

交互模式下:

非交互模式下:

[root@localhost test]# echo "3.4 + 5.88" | bc
9.28
[root@localhost test]# echo "3.4 * 5.88" | bc
19.99

使用scale可以指定输出小数的位数:

[root@localhost test]# echo "scale=2;837/32" | bc
26.15
[root@localhost test]# echo "scale=3;837/32" | bc
26.156
[root@localhost test]# echo "scale=4;837/32" | bc
26.1562

另外,bc命令也可以使用内置变量ibase(in)和obase(out)进行进制转换。

ibase:指定输入数字的进制

obase:指定输出数字的进制

# 输入二进制的1110,输出十进制的14
[root@localhost test]# echo "ibase=2;1110" | bc
14
# 输入十进制的10,输出二进制的1010
[root@localhost test]# echo "obase=2;10" | bc
1010
# 输入十六进制的FF,输出十进制的255
[root@localhost test]# echo "ibase=16;FF" | bc
255

最近发表
标签列表