Linux Bash Shell编程(七):字符串截取与处理(cut、printf、awk、sed、sort)含示例
上一节中,我们了解了正则表达式的基本作用及其用法。本节我们来研究字符串截取、格式化输出、字符串处理命令
cut 命令
cut命令是Bash中的字符串截取命令,可以将一个行中带有统一分割符(任意)的文件截取出其中几列
cut [options] <filename>
选项 | 说明 |
---|---|
-b | 只选中指定的这些字节 |
-c | 只选中指定的这些字符 |
-f | 只选中指定的这些域 |
-d | 使用指定的分界符(默认为
tab 制表符)(在-f模式下使用) 分界符必须是单个字符 |
-s | 不显示没有包含分界符的行(在-f模式下使用) ,默认显示 |
- 其中,前三项是必选项,且为互斥选项(三选一),
-d
表示以字节分隔,
-c
表示以字符分隔,
-f
表示以分界符分隔(形成可能包含多个字符或者空的域),一般域分隔较常用
- 若一行中没有包含分界符,则该命令会将改行整行输出,除非指定
-s
选项
-
-f
选项后需要域序号参数,可以是多行(以逗号分隔),也可以是集合(a-b)
-
-d
选项指定分界符,需要用单引号包含,可以是空格
- cut命令可能存在局限,但语法较简单,容易实现
示例:
#截取用户配置文件passwd文件中,所有用户名以及对应UIDcut -s -d \":\" -f 1,3 passwdroot:0daemon:1bin:2#文件内容仅截取部分#截取passwd文件中,所有组的附加用户cut -d \":\" -f 1,4 gshadowroot:daemon:bin:cdrom:zhengfloppy:zheng#文件内容仅截取部分#截取所有非root非系统用户zheng@Kali:~/temp$ grep \"/bin/bash\" /etc/passwd | cut -d \":\" -f 1rootpostgres #这个用户是某些服务需要的管理用户,同样具有可bash登录特性,需要额外排除zhengtest
printf 命令
printf是bash的格式化输出命令,printf也可以在awk命令中作为标准输出,用来输出允许定义格式的字符串\\数字内容,语法类似于C语言中的printf格式化输出命令
printf \'<输出类型><输出格式>\' <输出内容>#输出类型字符串中同样可以加入字符串用于说明,输出内容可以专注于变量等
- 输出类型和输出格式需要用单引号包含
- 输出内容一般为数字、变量等,以空格分隔
输出类型 | 说明 |
---|---|
%ns | 输出字符串,n为数字,表示输出几个字符(n可不加) |
%ni | 输出整数,n为数字,表示输出几个数字(n可不加) |
%m.nf | 输出浮点数字,m和n是数字,表示输出的数字位数(包括整数和小数)和小数位数 %4.3f 表示输出含一位整数和四位小数的数字 |
- printf命令的输出格式与
echo
命令的完全相同,这里不再赘述,请参阅Linux Bash Shell编程(一):Shell概述与Hello World实现
示例:
#将输出内容识别为字符串类型输出printf \'%s\' 1 2 as 12 312as123 #此行后没有换行符,直接开始下一行printf \'%s\\n\' 1 2 as 12 #按字符串输出,并且每个输出内容后增加换行符12as12#按字符串输出,并且三个一组增加空格和换行printf \'%s %s %s\\n\' 1 2 as 12 4 31 2 as12 4 3#printf的输出格式中也可以增加一些文字内容,后面的内容专注于变量输出printf \'Hello, %s\\n\' \"Zheng\"Hello, Zheng
awk命令
相较于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/passwdBeginroot 0daemon 1bin 2sys 3End#可以看到,分界符在一开始(未读取数据前)就被定义,正常截取并输出了第一行#但如果没有使用 BEGIN 条件,而是将分界符定义与格式化输出放在一起awk \'{FS=\":\";print $1 \"\\t\" $3}\' /etc/passwdroot:x:0:0:root:/root:/bin/bashdaemon 1bin 2sys 3#在定义分界符之前,第一行数据就已经被读入,无法对第一行数据重新截取,导致整行输出
示例:
#下面的awk命令示例没有条件仅有动作df -h | awk \'{printf $1 \"\\t\" $5 \"\\t\" $6 \"\\n\"}\'文件系统 已用% 挂载点udev 0% /devtmpfs 1% /run/dev/sda5 38% /tmpfs 0% /dev/shmtmpfs 0% /run/locktmpfs 0% /sys/fs/cgroup/dev/sda1 28% /boottmpfs 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 138
在得到我们需要的占用率信息后,将其写入脚本比较大小即可,
#以下是脚本df中内容#!/bin/bash#Author:Zhengdeclare -i aa=$(df | grep \"/$\" | awk \'{print $5}\' | cut -d \"%\" -f 1)if [ $a -lt 80 ]; then #条件判断语句在后面内容中会讲到echo \"Storage space normal\" #如果a小于80elseecho \"Warning:Not enough storage space\" #如果a大于80fiecho -e \"root storage used $a%\"
得到效果:
0zheng@Kali:~/Shell$ ./df.shStorage space normalroot storage used 38%
awk命令的其他功能(如流程控制、函数编程等)还有很多,这里限于篇幅,就不再更深入探讨,有兴趣的朋友可以查阅其他资料
sed命令
sed是一种几乎包括在所有UNIX平台的轻量级流编辑器(可以接受来自管道符的数据流)。sed可以对数据进行选取、替换、删除、新增等操作
sed [选项] {脚本} [文件]
选项 | 说明 |
---|---|
-n | 静默输出(默认会将所有数据都输出到屏幕),只会把经过sed命令处理的行输出到屏幕 |
-i | 用sed的修改结果直接修改读入数据的文件,而不是由屏幕输出 |
动作 | 说明 |
---|---|
a | 追加,在当前行后添加任意行,除最后一行外,每行末尾需要加“\\”表示数据未结束 |
c | 行替换,用c后面的字符串替换原数据行,替换多行时,除最后一行每行末尾需要加“\\”表示数据未结束 |
i | 插入,在当前行前插入任意行,多行同样加\”\” |
d | 删除指定的行 |
p | 打印,输出指定的行 |
s | 字串替换,用一个字符串替换另外一个字符串,格式为“行范围s/旧字串/新字串/g”(与vim中相似) |
- 输出时一般建议启用
-n
选项,否则该命令会将读取到的所有行重新输出一遍
- 追加、插入、行替换命令如果修改多行,则在动作后空格插入第一行内容,后用反斜杠回车,继续插入后面内容
示例:
#以下是示例文件b中内容ID Name gender Mark1 LiHua M 862 HZ M 903 Cooper M 89#下面开始测试#测试1:追加动作a(多行)sed \'4a End\\> Hello World\' bID Name gender Mark1 LiHua M 862 HZ M 903 Cooper M 89EndHello World#测试2:行替换命令sed \'4c Cooper Absent\\> End\' bID Name gender Mark1 LiHua M 862 HZ M 90Cooper AbsentEnd#测试3:插入命令sed \'1i Test Results\' bTest ResultsID Name gender Mark1 LiHua M 862 HZ M 903 Cooper M 89#测试4:删除行命令sed \'2,4d\' b #注意,逗号表示行范围的始末,非单独行ID Name gender Mark#测试4:输出指定的行sed -n \'3p\' b2 HZ M 90#测试5:字符串替换sed \'4s/M/F/g\' bID Name gender Mark1 LiHua M 862 HZ M 903 Cooper F 89
sort命令
sort命令对字符串行按一定的顺序排序
sort [options] [filename]
选项 | 说明 |
---|---|
-f | 忽略大小写 |
-n | 以数值型进行排序(默认字符串型) |
-r | 倒序排序 |
-t | 按照指定分隔符(默认tab制表符) |
-k n,m | 按照指定的字段范围排序,从n字段开始,m结束(默认到行尾) |
- -k 选项的指定字段是指列,可以指定单个字段(-k n)
示例:
#以下是passwd原文件前几行内容root:x:0:0:root:/root:/bin/bashdaemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologinbin:x:2:2:bin:/bin:/usr/sbin/nologinsys:x:3:3:sys:/dev:/usr/sbin/nologinsync:x:4:65534:sync:/bin:/bin/sync#按用户名字符串排序sort /etc/passwd_apt:x:100:65534::/nonexistent:/usr/sbin/nologinavahi:x:124:129:Avahi mDNS daemon,,,:/run/avahi-daemon:/usr/sbin/nologinbackup:x:34:34:backup:/var/backups:/usr/sbin/nologin#按组ID排序(需要指定分隔符,且排序依据为数字型)sort -t \":\" -k 4 -n /etc/passwdroot:x:0:0:root:/root:/bin/bashdaemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologinbin:x:2:2:bin:/bin:/usr/sbin/nologinsys:x:3:3:sys:/dev:/usr/sbin/nologinlp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin
索引
下一节,Linux Bash Shell编程(八):条件判断与示例 我们将开始学习Bash中的条件判断和流程控制语句
上一节 ,Linux Bash Shell编程(六):正则表达式 基本元字符应用示例