【1】字符提取与输出格式化
① cut列提取命令
语法格式
cut [选项] 文件名
选项:
- -f 列号: 提取第几列
- -d 分隔符: 按照指定分隔符分割列
- -c 字符范围: 不依赖分隔符来区分列,而是通过字符范围(行首为0)来进行字段提取。“n-”表示从第n个字符到行尾;“n-m”从第n个字符到第m个字符;“-m”表示从第1个字符到第m个字符。
cut命令的默认分隔符是制表符,也就是“tab”键。
测试文本如下(用Tab键分割):
测试实例如下:
#提取第二列内容 [root@bogon shell]# cut -f 2 student.txt Name Liming Sc Tg #提取2 3列内容 [root@bogon shell]# cut -f 2,3 student.txt Name gender Liming M Sc M Tg M
cut可以按照字符进行提取,需要注意“8-”代表的是提取所有行的第8个字符开始到行尾,而“10-20”代表提取所有行的第十个字符到第二十个字符,而“-8”代表提取所有行从行首到第八个字符:
[root@bogon shell]# cut -c 8- student.txt gender Mark g M 86 90 83
以“:”
作为分隔符,提取/etc/passwd文件的第一列和第三列
[root@bogon shell]# cut -d ":" -f 1,3 /etc/passwd root:0 bin:1 daemon:2 adm:3 lp:4 sync:5 shutdown:6 halt:7 mail:8 operator:11 games:12 ftp:14 nobody:99 systemd-network:192 //...
② printf格式化输出
语法格式:
printf '输出类型输出格式' 输出内容
输出类型:
%ns
: 输出字符串。n是数字指代输出几个字符(n可为0)%ni
: 输出整数。n是数字指代输出几个数字(n可为0)%m.nf
: 输出浮点数。m和n是数字,指代输出的整数位数和小数位数。如%8.2f代表共输出8位数,其中2位是小数,6位是整数。
输出格式:
- \a: 输出警告声音
- \b: 输出退格键,也就是Backspace键
- \f: 清除屏幕
- \n: 换行
- \r: 回车,也就是Enter键
- \t: 水平输出退格键,也就是Tab键
- \v: 垂直输出退格键,也就是Tab键
修改student.txt如下:
测试实例如下:
[root@bogon shell]# printf '%s' $(cat student.txt) IDNamePHPLinuxMySQLAverage1Liming82958687.662Sc74968785.663Tg99839391.66[root@bogon shell]#
可以看到文本内容直接平铺输出没有任何格式。这就是printf命令,如果不指定输出格式,则会把所有输出内容连在一起输出。
其实文本的输出本身就是这样的,cat等文本输出命令之所以可以按照格式漂亮的输出,那是因为cat命令已经设定了输出格式。
那么为了用printf输出合理的格式,应该这样做(注意在printf命令的单引号中,只能识别格式输出符号,而手工输入的空格是无效的):
[root@bogon shell]# printf '%s\t %s\t %s\t %s\t %s\t %s\t \n' $(cat student.txt) ID Name PHP Linux MySQL Average 1 Liming 82 95 86 87.66 2 Sc 74 96 87 85.66 3 Tg 99 83 93 91.66
如果不想把成绩当成字符串输出,而是按照整型和浮点型输出,则要这样:
#grep -v Name) 表示不包含Name那一行,即反向查找 [root@bogon shell]# printf '%i\t %s\t %i\t %i\t %i\t %8.2f\t \n' $(cat student.txt | grep -v Name) 1 Liming 82 95 86 87.66 2 Sc 74 96 87 85.66 3 Tg 99 83 93 91.66
awk中print与printf使用
如下实例,awk+print打印第二行数据:
[root@localhost shell]# cat student.txt ID Name PHP Linux MySQL Average 1 Liming 82 95 86 87.66 2 Sc 74 96 87 85.66 3 Tg 99 83 93 91.66 [root@localhost shell]# cat student.txt | awk 'NR==2{print}' 1 Liming 82 95 86 87.66
awk+printf 打印第二行数据:
[root@localhost shell]# awk 'NR==2{printf $0 "\n"}' student.txt 1 Liming 82 95 86 87.66
【2】awk编程
awk是一种编程语言,用于在linux/unix下对文本和数据进行处理。数据可以来自标准输入(stdin)、一个或多个文件,或其它命令的输出。它支持用户自定义函数和动态正则表达式等先进功能,是linux/unix下的一个强大编程工具。它在命令行中使用,但更多是作为脚本来使用。awk有很多内建的功能,比如数组、函数等,这是它和C语言的相同之处,灵活性是awk最大的优势。可以点击参考更多awk介绍。
常用命令选项
-F fs fs指定输入分隔符,fs可以是字符串或正则表达式,如-F:
-v var=value 赋值一个用户定义变量,将外部变量传递给awk
-f scripfile 从脚本文件中读取awk命令
-m[fr] val 对val值设置内在限制,-mf选项限制分配给val的最大块数目;-mr选项限制记录的最大数目。这两个功能是Bell实验室版awk的扩展功能,在标准awk中不适用。
① awk的基本语法
语法格式如下:
awk '条件1{动作1} 条件2{动作2}…' 文件名 #完整格式如下 awk 'BEGIN{ print "start" } pattern{ commands } END{ print "end" }' file
条件(Pattern):
一般使用关系表达式作为条件,这些关系表达式非常多。例如:
x > 10 判断变量 x是否大于10
x == y 判断变量 x是否等于变量y
A ~ B 判断字符串A中是否包含能匹配B 表达式的子字符串
A !~ B 判断字符串A中是否不包含能匹配B表达式的子字符串
动作(Action):
格式化输出
流程控制语句
使用awk+printf进行输出:
#输出第二列和第六列 [root@localhost shell]# awk '{printf $2 "\t" $6 "\n"}' student.txt Name Average Liming 87.66 Sc 85.66 Tg 91.66 #效果等同于如下 [root@localhost shell]# cut -f 2,6 student.txt Name Average Liming 87.66 Sc 85.66 Tg 91.66
输出df -h的第一列和第三列:
[root@localhost shell]# df -h |awk '{printf $1 "\t" $3 "\n"}' Filesystem Used devtmpfs 0 tmpfs 0 tmpfs 8.4M tmpfs 0 /dev/mapper/centos-root 5.4G /dev/sda1 171M tmpfs 12K tmpfs 0
② awk的条件
条件的类型 | 条 件 | 说 明 |
awk保留字 | BEGIN | 在awk程序一开始时,尚未读取任何数据之前执行。BEGIN后的动作只在程序开始时执行一次 |
awk保留字 | END | 在awk程序处理完所有数据,即将结束时执行。END后的动作只在程序结束时执行一次 |
关系运算符 | > | 大于 |
< |
小于 | |
>= | 大于等于 | |
<= | 小于等于 | |
== | 等于。用于判断两个值是否相等,如果是给变量赋值,请使用“=”号 | |
!= | 不等于 | |
A~B | 判断字符串A中是否包含能匹配B 表达式的子字符串 |
A!~B |
判断字符串A中是否不包含能匹配B表达式的子字符串 | |
正则表达式 | /正则/ |
在“//” 中可以写入字符,也可以支持正则表达式 |
BEGIN
BEGIN是awk的保留字,是一种特殊的条件类型。BEGIN的执行时机是“在awk程序一开始时,尚未读取任何数据之前执行”。一旦BEGIN后的动作执行一次,当awk开始从文件中读入数据,BEGIN的条件就不再成立,所以BEGIN定义的动作只能被执行一次。
如下所示,在程序开始时打印“这是一张成绩单”,然后输出student.txt中的第2列和第6列:
[root@localhost shell]# awk 'BEGIN{printf "This is a transcript \n"} {printf $2 "\t" $6 "\n"}' student.txt This is a transcript Name Average Liming 87.66 Sc 85.66 Tg 91.66
END
END也是awk保留字,不过刚好和BEGIN相反。END是在awk程序处理完所有数据,即将结束时执行。END后的动作只在程序结束时执行一次。
测试实例如下:
[root@localhost shell]# awk 'END{printf "This is end \n"} {printf $2 "\t" $6 "\n"}' student.txt Name Average Liming 87.66 Sc 85.66 Tg 91.66 This is end
关系运算符
如下输出平均分大于等于97的学生姓名:
[root@localhost shell]# cat student.txt | grep -v Name 1 Liming 82 95 86 87.66 2 Sc 74 96 87 85.66 3 Tg 99 83 93 91.66 [root@localhost shell]# cat student.txt | grep -v Name|awk '$6>=87{printf $2 "\n"}' Liming Tg
加入了条件之后,只有条件成立动作才会执行,如果条件不满足,则动作则不运行。通过这个实验可以发现,虽然awk是列提取命令,但是也要按行来读入的。这个命令的执行过程是这样的:
1) 如果有BEGIN条件,则先执行BEGIN定义的动作
2) 如果没有BEGIN条件,则读入第一行,把第一行的数据依次赋予$0、$1、$2等变量。其中$0代表此行的整体数据,$1代表第一字段,$2代表第二字段。
3) 依据条件类型判断动作是否执行。如果条件符合,则执行动作,否则读入下一行数据。如果没有条件,则每行都执行动作。
4) 读入下一行数据,重复执行以上步骤。
如下查询Sc用户的平均分:
[root@localhost shell]# awk '$2~/Sc/{printf $6 "\n"}' student.txt 85.66
这里要注意在awk中,使用“//”
包含的字符串,awk命令才会查找。也就是说字符串必须用“//”
包含,awk命令才能正确识别。
正则表达式
如果要想让awk识别字符串,必须使用“//”包含。当使用df命令查看分区使用情况是,如果我只想查看真正的系统分区的使用状况,而不想查看光盘和临时分区的使用状况,则可以
[root@localhost shell]# df -h |awk '/sda[0-9]/{printf $1 "\t" $5 "\n"}' /dev/sda1 17% #如果想获取17则可以和cut命令配合使用 [root@localhost shell]# df -h |awk '/sda[0-9]/{print $5 "\n"}'|cut -d "%" -f 1 17
③ awk内置变量
awk内置变量 | 作 用 |
$0 |
代表目前awk所读入的整行数据。我们已知awk是一行一行读入数据的,$0就代表当前读入行的整行数据 |
$n |
代表目前读入行的第n个字段 |
NF | 当前行拥有的字段(列)总数 |
NR | 当前awk所处理的行,是总数据的第几行 |
FS | 用户定义分隔符。awk的默认分隔符是任何空格,如果想要使用其他分隔符(如“:”),就需要FS变量定义 |
ARGC | 命令行参数个数 |
ARGV | 命令行参数数组 |
FNR | 当前文件中的当前记录数(对输入文件起始为1) |
OFMT | 数值的输出格式(默认为%.6g ) |
OFS | 输出字段的分隔符(默认为空格) |
ORS | 输出记录分隔符(默认为换行符) |
RS | 输入记录分隔符(默认为换行符) |
读取登录用户的名称和用户标识号(用户名:口令:用户标识号:组标识号:注释性描述:主目录:登录Shell
)
[root@localhost shell]# cat /etc/passwd | grep "/bin/bash" | awk '{FS=":"} {printf $1 "\t" $3 "\n"}' root:x:0:0:root:/root:/bin/bash jane 1000
可以看到第一行的{FS=":"}
并没有起作用,第二行才开始起作用。这是因为没有使用BEGIN保留字,awk读入每行数据后会判断是否有begin,如果没有begin则根据条件执行每个动作。修改命令如下:
[root@localhost shell]# cat /etc/passwd | grep "/bin/bash" | awk 'BEGIN{FS=":"} {printf $1 "\t" $3 "\n"}' root 0 jane 1000
在上面基础上继续输出当前行号和字段数:
[root@localhost shell]# cat /etc/passwd | grep "/bin/bash" | awk 'BEGIN{FS=":"} {printf $1 "\t" $3 "\t 行号:"NR "\t 字符数:"NF "\n"}' root 0 行号:1 字符数:7 jane 1000 行号:2 字符数:7
如果我只想看看sshd这个伪用户的相关信息,则可以这样使用:
[root@localhost shell]# cat /etc/passwd | awk 'BEGIN{FS=":"} $1=="sshd"{printf $1 "\t" $3 "\t 行号:"NR "\t 字符数:"NF "\n"}' sshd 74 行号:40 字符数:7
④ awk流程控制
4.1在awk中定义变量与调用变量的值
统计PHP成绩的总分实例如下:
[root@localhost shell]# awk 'NR==2{php1=$3} NR==3{php2=$3} NR==4{php3=$3;totle=php1+php2+php3;printf "totle php is " totle "\n"}' student.txt totle php is 255
在awk编程中,因为命令语句非常长,在输入格式时需要注意以下内容:
多个条件{动作}可以用空格分割,也可以用回车分割。
在一个动作中,如果需要执行多个命令,需要用“;”分割,或用回车分割。
在awk中,变量的赋值与调用都不需要加入“$”符。
条件中判断两个值是否相同,请使用“==”,以便和变量赋值进行区分。
如下输出Linux成绩大于90的:
[root@localhost shell]# awk '{if(NR>=2){if($4>=90){printf $2 "\tis a good man\n"}}}' student.txt Liming is a good man Sc is a good man # 这里里侧{}可以去掉,如下所示 [root@localhost shell]# awk '{if(NR>=2){if($4>=90)printf $2 "\tis a good man\n"}}' student.txt Liming is a good man Sc is a good man #还可以修改如下 [root@localhost shell]# awk 'NR>=2{if($4>=90)printf $2 "\tis a good man\n"}' student.txt Liming is a good man Sc is a good man #在awk中if判断语句,完全可以直接利用awk自带的条件来取代 [root@localhost shell]# awk 'NR>=2{test=$4} test>=90{printf $2 "\tis a good man\n"}' student.txt Liming is a good man Sc is a good man
⑤ awk函数
awk编程也允许在编程时使用函数,awk函数的定义方法如下:
function 函数名(参数列表){ 函数体 }
如下所示打印学生成绩:
[root@localhost shell]# awk 'function test(a,b){printf a "\t" b "\n"} {test($2,$6)}' student.txt Name Average Liming 87.66 Sc 85.66 Tg 91.66
⑥ awk中调用脚本
对于小的单行程序来说,将脚本作为命令行自变量传递给awk是非常简单的,而对于多行程序就比较难处理。当程序是多行的时候,使用外部脚本是很适合的。首先在外部文件中写好脚本,然后可以使用awk的-f选项
,使其读入脚本并且执行。
例如,我们可以先编写一个awk脚本
[root@localhost ~]# vi pass.awk BEGIN {FS=":"} { print $1 "\t" $3}
然后可以使用“-f”
选项来调用这个脚本:
[root@localhost ~]# awk -f pass.awk /etc/passwd root 0 bin 1 daemon 2 //...
⑦ 应用案例
重启springboot
#!/bin/bash #jar名字 project=yihuiyuan-0.0.1-SNAPSHOT.jar num=$(ps -ef|grep $project| wc -l) for (( i=1;i<=$num;i++ )) do pid=$( ps -ef|grep $project| awk -v row=$i 'NR==row{printf $2 "\n"}') if [ -n "$pid" ];then kill -9 $pid fi done if [ -f nohup.out ];then rm -rf ./nohup.out fi if [ -f "$project" ];then rm -rf ./"$project" touch nohup.out fi #假设新的jar放在了脚本的上一级目录 mv ../"$project" ./ nohup java -jar "$project" &>nohup.out & tail -f nohup.out
【3】sed命令
sed主要是用来将数据进行选取、替换、删除、新增的命令,语法格式如下:
sed [选项] ‘[动作]’ 文件名
选项:
-n: 一般sed命令会把所有数据都输出到屏幕,如果加入此选择,则只会把经过sed命令处理的行输出到屏幕。
-e: 允许对输入数据应用多条sed命令编辑。
-f 脚本文件名: 从sed脚本中读入sed操作。和awk命令的-f非常类似。
-r: 在sed中支持扩展正则表达式。
-i: 用sed的修改结果直接修改读取数据的文件,而不是由屏幕输出
动作:
a \: 追加,在当前行后添加一行或多行。添加多行时,除最后 一行外,每行末尾需要用“\”代表数据未完结。
c \: 行替换,用c后面的字符串替换原数据行,替换多行时,除最后一行外,每行末尾需用“\”代表数据未完结。
i \: 插入,在当期行前插入一行或多行。插入多行时,除最后 一行外,每行末尾需要用“\”代表数据未完结。
d: 删除,删除指定的行。
p: 打印,输出指定的行。
s: 字串替换,用一个字符串替换另外一个字符串。格式为“行范围s/旧字串/新字串/g”(和vim中的替换格式类似)。
对sed命令大家要注意,sed所做的修改并不会直接改变文件的内容(如果是用管道符接收的命令的输出,这种情况连文件都没有),而是把修改结果只显示到屏幕上,除非使用“-i”选项才会直接修改文件。
操作实例
打印student.txt第二行数据:
[root@localhost shell]# sed -n "2p" student.txt 1 Liming 82 95 86 87.66
删除第二行到第四行的数据:
[root@localhost shell]# sed "2,4d" student.txt ID Name PHP Linux MySQL Average #但是文件本身并没有修改 [root@localhost shell]# cat student.txt ID Name PHP Linux MySQL Average 1 Liming 82 95 86 87.66 2 Sc 74 96 87 85.66 3 Tg 99 83 93 91.66
在第二行后插入数据:
[root@localhost shell]# sed "2a hello" student.txt ID Name PHP Linux MySQL Average 1 Liming 82 95 86 87.66 hello 2 Sc 74 96 87 85.66 3 Tg 99 83 93 91.66
在第二行前插入数据:
[root@localhost shell]# sed "2i hello" student.txt ID Name PHP Linux MySQL Average hello 1 Liming 82 95 86 87.66 2 Sc 74 96 87 85.66 3 Tg 99 83 93 91.66
如果是想追加或插入多行数据,除最后一行外,每行的末尾都要加入“\”代表数据未完结:
[root@localhost shell]# sed '2i hello \ > world' student.txt ID Name PHP Linux MySQL Average hello > world 1 Liming 82 95 86 87.66 2 Sc 74 96 87 85.66 3 Tg 99 83 93 91.66
加上-n只查看sed处理过的数据:
[root@localhost shell]# sed -n '2i hello \ world' student.txt hello world
行数据替换(替换掉第二行数据):
[root@localhost shell]# cat student.txt | sed '2c No such person' ID Name PHP Linux MySQL Average No such person 2 Sc 74 96 87 85.66 3 Tg 99 83 93 91.66
sed命令默认情况是不会修改文件内容的,如果确定需要让sed命令直接处理文件的内容,可以使用“-i”
选项。如下所示修改文本第二行数据:
[root@localhost shell]# sed -i '2c No such person' student2.txt [root@localhost shell]# cat student2.txt ID Name PHP Linux MySQL Average No such person 2 Sc 74 96 87 85.66 3 Tg 99 83 93 91.66
字符串替换
“c”动作是进行整行替换的,如果仅仅想替换行中的部分数据,就要使用“s”动作了。s动作的格式是:sed ‘s/旧字串/新字串/g’ 文件名
操作实例如下:
#把第三行的74 改为 99 [root@localhost shell]# sed '3s/74/99/g' student.txt ID Name PHP Linux MySQL Average 1 Liming 82 95 86 87.66 2 Sc 99 96 87 85.66 3 Tg 99 83 93 91.66 #第四行手添加#号表示注释 [root@localhost shell]# sed '4s/^/#/g' student2.txt ID Name PHP Linux MySQL Average No such person 2 Sc 74 96 87 85.66 #3 Tg 99 83 93 91.66
同时处理多行
“-e”
选项可以同时执行多个sed动作,当然如果只是执行一个动作也可以使用“-e”
选项,但是这时没有什么意义。还要注意,多个动作之间要用“;”
号或回车
分割。
[root@localhost shell]# cat student2.txt ID Name PHP Linux MySQL Average 1 Liming 82 95 86 87.66 2 Sc 74 96 87 85.66 3 Tg 99 83 93 91.66 [root@localhost shell]# sed -e 's/Liming//g ; s/Tg//g' student2.txt ID Name PHP Linux MySQL Average 1 82 95 86 87.66 2 Sc 74 96 87 85.66 3 99 83 93 91.66 #可以修改如下 [root@localhost ~]# sed -e 's/Liming//g > s/Tg//g' student2.txt
【4】字符处理命令
① 排序命令sort
语法格式:sort [选项] 文件名
选项:
- -f: 忽略大小写
- -b: 忽略每行前面的空白部分
- -n: 以数值型进行排序,默认使用字符串型排序
- -r: 反向排序
- -u: 删除重复行。就是uniq命令
- -t: 指定分隔符,默认是分隔符是制表符
- -k n[,m]: 按照指定的字段范围排序。从第n字段开始,m字段结束(默认到行尾)
sort命令默认是用每行开头第一个字符来进行排序的,如对student.txt默认排序如下:
[root@localhost shell]# sort student.txt 1 Liming 82 95 86 87.66 2 Sc 74 96 87 85.66 3 Tg 99 83 93 91.66 ID Name PHP Linux MySQL Average
反向排序:
[root@localhost shell]# sort -r student.txt ID Name PHP Linux MySQL Average 3 Tg 99 83 93 91.66 2 Sc 74 96 87 85.66 1 Liming 82 95 86 87.66
以第三列字段排序:
[root@localhost shell]# sort -k 3,3 student.txt 2 Sc 74 96 87 85.66 1 Liming 82 95 86 87.66 3 Tg 99 83 93 91.66 ID Name PHP Linux MySQL Average
当然“-k”选项可以直接使用“-k 3”,代表从第三字段到行尾都排序(第一个字符先排序,如果一致,第二个字符再排序,知道行尾)。
删除重复行:
#如下首先快速复制一行 ID Name PHP Linux MySQL Average 1 Liming 82 95 86 87.66 1 Liming 82 95 86 87.66 2 Sc 74 96 87 85.66 3 Tg 99 83 93 91.66 #使用 -u选项取消重复行 [root@localhost shell]# sort -u student2.txt 1 Liming 82 95 86 87.66 2 Sc 74 96 87 85.66 3 Tg 99 83 93 91.66 ID Name PHP Linux MySQL Average #但是并不会改变源文件 [root@localhost shell]# cat student2.txt ID Name PHP Linux MySQL Average 1 Liming 82 95 86 87.66 1 Liming 82 95 86 87.66 2 Sc 74 96 87 85.66 3 Tg 99 83 93 91.66
② uniq命令
其实是对应unique(单独、唯一),uniq命令是用来取消重复行的命令,和“sort -u”选项是一样的。命令格式如下:
uniq [选项] 文件名
选项:
- -i: 忽略大小写
- -d:打印重复行的一行
- -D:打印所有重复行
- -u:打印非重复行
[root@localhost shell]# uniq -d student2.txt 1 Liming 82 95 86 87.66 [root@localhost shell]# uniq -D student2.txt 1 Liming 82 95 86 87.66 1 Liming 82 95 86 87.66 [root@localhost shell]# uniq -u student2.txt ID Name PHP Linux MySQL Average 2 Sc 74 96 87 85.66 3 Tg 99 83 93 91.66
【5】 统计命令wc
wc命令用来计算数字。利用wc指令我们可以计算文件的Byte数、字数或是列数,若不指定文件名称,或是所给予的文件名为“-”,则wc指令会从标准输入设备读取数据。
语法:
wc(选项)(参数)
选项:
-c: 统计字节数Bytes -l: 只统计行数 -w: 只统计单词数 -m: 只统计字符数
参数:
文件:需要统计的文件列表。
实例
#文件实例 [root@localhost shell]# cat student2.txt ID Name PHP Linux MySQL Average 1 Liming 82 95 86 87.66 中 Liming 82 95 86 87.66 2 Sc 74 96 87 85.66 3 Tg 99 83 93 91.66 #统计单词数 [root@localhost shell]# wc -w student2.txt 30 student2.txt #统计字符数 [root@localhost shell]# wc -m student2.txt 120 student2.txt #统计字节数 [root@localhost shell]# wc -c student2.txt 122 student2.txt #统计行数 [root@localhost shell]# wc -l student2.txt 5 student2.txt