上一节中,我们了解了正则表达式的基本作用及其用法。本节我们来研究字符串截取、格式化输出、字符串处理命令
cut命令是Bash中的字符串截取命令,可以将一个行中带有统一分割符(任意)的文件截取出其中几列
cut [options] <filename>
选项 | 说明 |
---|---|
-b | 只选中指定的这些字节 |
-c | 只选中指定的这些字符 |
-f | 只选中指定的这些域 |
-d | 使用指定的分界符(默认为tab 制表符)(在-f模式下使用) 分界符必须是单个字符 |
-s | 不显示没有包含分界符的行(在-f模式下使用) ,默认显示 |
-d
表示以字节分隔,-c
表示以字符分隔,-f
表示以分界符分隔(形成可能包含多个字符或者空的域),一般域分隔较常用-s
选项-f
选项后需要域序号参数,可以是多行(以逗号分隔),也可以是集合(a-b)-d
选项指定分界符,需要用单引号包含,可以是空格示例:
#截取用户配置文件passwd文件中,所有用户名以及对应UID
cut -s -d ":" -f 1,3 passwd
root:0
daemon:1
bin:2
#文件内容仅截取部分
#截取passwd文件中,所有组的附加用户
cut -d ":" -f 1,4 gshadow
root:
daemon:
bin:
cdrom:zheng
floppy:zheng
#文件内容仅截取部分
#截取所有非root非系统用户
zheng@Kali:~/temp$ grep "/bin/bash" /etc/passwd | cut -d ":" -f 1
root
postgres #这个用户是某些服务需要的管理用户,同样具有可bash登录特性,需要额外排除
zheng
test
printf是bash的格式化输出命令,printf也可以在awk命令中作为标准输出,用来输出允许定义格式的字符串\数字内容,语法类似于C语言中的printf格式化输出命令
printf '<输出类型><输出格式>' <输出内容>
#输出类型字符串中同样可以加入字符串用于说明,输出内容可以专注于变量等
输出类型 | 说明 |
---|---|
%ns | 输出字符串,n为数字,表示输出几个字符(n可不加) |
%ni | 输出整数,n为数字,表示输出几个数字(n可不加) |
%m.nf | 输出浮点数字,m和n是数字,表示输出的数字位数(包括整数和小数)和小数位数 %4.3f 表示输出含一位整数和四位小数的数字 |
echo
命令的完全相同,这里不再赘述,请参阅Linux Bash Shell编程(一):Shell概述与Hello World实现示例:
#将输出内容识别为字符串类型输出
printf '%s' 1 2 as 12 3
12as123 #此行后没有换行符,直接开始下一行
printf '%s\n' 1 2 as 12 #按字符串输出,并且每个输出内容后增加换行符
1
2
as
12
#按字符串输出,并且三个一组增加空格和换行
printf '%s %s %s\n' 1 2 as 12 4 3
1 2 as
12 4 3
#printf的输出格式中也可以增加一些文字内容,后面的内容专注于变量输出
printf 'Hello, %s\n' "Zheng"
Hello, Zheng
相较于cut命令,awk命令的功能更加强大,可以截取以不同长度空格分隔的字符串,对字符串进行函数编程、条件判断、流程控制等操作。但同时,其语言结构较cut也更加复杂,类似于编程语言。
awk 'pattern1{action1}pattern2{action2}...' <filename>
pattern:条件,一般为关系表达式(例如 x>1),可以为空,缺省不经过条件判断,全部执行动作
action:动作,可以是格式化输出(awk支持printf、print)命令或流程控制语句
awk命令仍然将输入内容按行处理
printf
命令与print
命令的差别仅在于,后者在输出结束后自动加入换行符,而前者不会
awk命令读取行字符串后,将其中内容按分隔符分开(若存在多个空格也能分隔),用$n
表示,n为数字,$0
表示整行内容,$1
表示第一列,$2
表示第二列,以此类推
awk命令提供一个预制变量FS
作为分隔符,该命令默认对tab
、space
有效,但如果是其他符号,则需要预设,通常使用BEGIN
条件预设
BEGIN条件,作为一个pattern
使用,声明BEGIN
条件的action
在awk命令读取第一行字符串前就执行,可以进行需要预先执行一次的命令
END条件,用法同BEGIN,在所有内容都读取完成后执行一次
例如:需要在截取passwd变量前进行分界符的定义,
awk 'BEGIN{FS=":";print "Begin"}END{print "End"}{print $1 "\t" $3}' /etc/passwd
Begin
root 0
daemon 1
bin 2
sys 3
End
#可以看到,分界符在一开始(未读取数据前)就被定义,正常截取并输出了第一行
#但如果没有使用 BEGIN 条件,而是将分界符定义与格式化输出放在一起
awk '{FS=":";print $1 "\t" $3}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon 1
bin 2
sys 3
#在定义分界符之前,第一行数据就已经被读入,无法对第一行数据重新截取,导致整行输出
示例:
#下面的awk命令示例没有条件仅有动作
df -h | awk '{printf $1 "\t" $5 "\t" $6 "\n"}'
文件系统 已用% 挂载点
udev 0% /dev
tmpfs 1% /run
/dev/sda5 38% /
tmpfs 0% /dev/shm
tmpfs 0% /run/lock
tmpfs 0% /sys/fs/cgroup
/dev/sda1 28% /boot
tmpfs 1% /run/user/1000
下面的示例提供了检查根目录挂载的文件系统占用率并在过高时报警的功能
首先,现在命令行中使用管道符逐步截取需要的占用量内容
#原理:使用df命令查看文件系统占用信息
df
#筛选出需要的根目录挂载信息,每一行以挂载位置结尾,根目录仅有"\",可以作为判断依据
df | grep "/$"
#正则表达式内容见上一节
#接下来得到一行信息,该信息以space分隔,需要使用awk截取命令,获得第五列信息
df | grep "/$" | awk '{print $5}'
#接下来,需要将百分号去掉,仅需要一个数字
df | grep "/$" | awk '{print $5}' | cut -d "%" -f 1
#由于占用率可能是一位或两位,稳妥方法使用域截取
#命令结果是需要的正确信息
df | grep "/$" | awk '{print $5}' | cut -d "%" -f 1
38
在得到我们需要的占用率信息后,将其写入脚本比较大小即可,
#以下是脚本df中内容
#!/bin/bash
#Author:Zheng
declare -i a
a=$(df | grep "/$" | awk '{print $5}' | cut -d "%" -f 1)
if [ $a -lt 80 ]; then #条件判断语句在后面内容中会讲到
echo "Storage space normal" #如果a小于80
else
echo "Warning:Not enough storage space" #如果a大于80
fi
echo -e "root storage used $a%"
得到效果:
0zheng@Kali:~/Shell$ ./df.sh
Storage space normal
root storage used 38%
awk命令的其他功能(如流程控制、函数编程等)还有很多,这里限于篇幅,就不再更深入探讨,有兴趣的朋友可以查阅其他资料
sed是一种几乎包括在所有UNIX平台的轻量级流编辑器(可以接受来自管道符的数据流)。sed可以对数据进行选取、替换、删除、新增等操作
sed [选项] {脚本} [文件]
选项 | 说明 |
---|---|
-n | 静默输出(默认会将所有数据都输出到屏幕),只会把经过sed命令处理的行输出到屏幕 |
-i | 用sed的修改结果直接修改读入数据的文件,而不是由屏幕输出 |
动作 | 说明 |
---|---|
a | 追加,在当前行后添加任意行,除最后一行外,每行末尾需要加“\”表示数据未结束 |
c | 行替换,用c后面的字符串替换原数据行,替换多行时,除最后一行每行末尾需要加“\”表示数据未结束 |
i | 插入,在当前行前插入任意行,多行同样加"" |
d | 删除指定的行 |
p | 打印,输出指定的行 |
s | 字串替换,用一个字符串替换另外一个字符串,格式为“行范围s/旧字串/新字串/g”(与vim中相似) |
-n
选项,否则该命令会将读取到的所有行重新输出一遍示例:
#以下是示例文件b中内容
ID Name gender Mark
1 LiHua M 86
2 HZ M 90
3 Cooper M 89
#下面开始测试
#测试1:追加动作a(多行)
sed '4a End\
> Hello World' b
ID Name gender Mark
1 LiHua M 86
2 HZ M 90
3 Cooper M 89
End
Hello World
#测试2:行替换命令
sed '4c Cooper Absent\
> End' b
ID Name gender Mark
1 LiHua M 86
2 HZ M 90
Cooper Absent
End
#测试3:插入命令
sed '1i Test Results' b
Test Results
ID Name gender Mark
1 LiHua M 86
2 HZ M 90
3 Cooper M 89
#测试4:删除行命令
sed '2,4d' b #注意,逗号表示行范围的始末,非单独行
ID Name gender Mark
#测试4:输出指定的行
sed -n '3p' b
2 HZ M 90
#测试5:字符串替换
sed '4s/M/F/g' b
ID Name gender Mark
1 LiHua M 86
2 HZ M 90
3 Cooper F 89
sort命令对字符串行按一定的顺序排序
sort [options] [filename]
选项 | 说明 |
---|---|
-f | 忽略大小写 |
-n | 以数值型进行排序(默认字符串型) |
-r | 倒序排序 |
-t | 按照指定分隔符(默认tab制表符) |
-k n,m | 按照指定的字段范围排序,从n字段开始,m结束(默认到行尾) |
示例:
#以下是passwd原文件前几行内容
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
sync:x:4:65534:sync:/bin:/bin/sync
#按用户名字符串排序
sort /etc/passwd
_apt:x:100:65534::/nonexistent:/usr/sbin/nologin
avahi:x:124:129:Avahi mDNS daemon,,,:/run/avahi-daemon:/usr/sbin/nologin
backup:x:34:34:backup:/var/backups:/usr/sbin/nologin
#按组ID排序(需要指定分隔符,且排序依据为数字型)
sort -t ":" -k 4 -n /etc/passwd
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
sys:x:3:3:sys:/dev:/usr/sbin/nologin
lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
下一节,Linux Bash Shell编程(八):条件判断与示例 我们将开始学习Bash中的条件判断和流程控制语句
上一节 ,Linux Bash Shell编程(六):正则表达式 基本元字符应用示例