语法格式
cut [选项] 文件名
选项:
cut命令的默认分隔符是制表符,也就是“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 '输出类型输出格式' 输出内容
输出类型:
%ns
: 输出字符串。n是数字指代输出几个字符(n可为0)%ni
: 输出整数。n是数字指代输出几个数字(n可为0)%m.nf
: 输出浮点数。m和n是数字,指代输出的整数位数和小数位数。如%8.2f代表共输出8位数,其中2位是小数,6位是整数。输出格式:
修改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打印第二行数据:
[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
awk是一种编程语言,用于在linux/unix下对文本和数据进行处理。数据可以来自标准输入(stdin)、一个或多个文件,或其它命令的输出。它支持用户自定义函数和动态正则表达式等先进功能,是linux/unix下的一个强大编程工具。它在命令行中使用,但更多是作为脚本来使用。awk有很多内建的功能,比如数组、函数等,这是它和C语言的相同之处,灵活性是awk最大的优势。可以点击参考更多awk介绍。
常用命令选项
语法格式如下:
awk '条件1{动作1} 条件2{动作2}…' 文件名
#完整格式如下
awk 'BEGIN{ print "start" } pattern{ commands } END{ print "end" }' file
条件(Pattern):
一般使用关系表达式作为条件,这些关系表达式非常多。例如:
动作(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保留字 | 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是列提取命令,但是也要按行来读入的
。这个命令的执行过程是这样的:
如下查询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内置变量 | 作 用 |
---|---|
$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
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编程中,因为命令语句非常长,在输入格式时需要注意以下内容:
条件{动作}
可以用空格分割,也可以用回车分割。“;”
分割,或用回车分割。“$”
符。“==”
,以便和变量赋值进行区分。如下输出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函数的定义方法如下:
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的-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
//...
sed主要是用来将数据进行选取、替换、删除、新增的命令,语法格式如下:
sed [选项] ‘[动作]’ 文件名
选项:
动作:
行范围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
语法格式:sort [选项] 文件名
选项:
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
其实是对应unique(单独、唯一),uniq命令是用来取消重复行的命令,和“sort -u”选项是一样的。命令格式如下:
uniq [选项] 文件名
选项:
[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
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