- cut、printf和awk三个字段提取命令与grep命令的区别是:grep命令在文件当中提取符合条件的行,cut命令和awk命令提取列。
- 一般cut不能独立使用,必须管道符和grep命令联合使用;
- 只有普通用户的权限才是/bin/bash文件,所有系统用户的权限都是/sbin/nilogin文件
[root@localhost ~]# cut [选项] 文件名
选项:
- -f 列号:提出第几列
- -d 分隔符:按照指定分隔符分割列。默认时候的分隔符是制表符,即“Tab”键
联系测试文件如下:
[root@root ~]# vi student.txt
ID Name gender Mark
1 Liming M 86
2 SC M 90
3 Gao M 83
[root@root ~]# cut -f 2 student.txt
Name
Liming
SC
Gao
[root@root ~]# cut -f 2,3 student.txt
Name gender
Liming M
SC M
Gao M
注意:/etc/passwd——>是用户信息文件
[root@root ~]# cut -d ":" -f 1,3 /etc/passwd
root:0
bin:1
daemon:2
adm:3
lp:4
sync:5
shutdown:6
... ...
在管道符中使用grep命令和cut命令的示例:
- cat /etc/passwd ——> 会列出所有的passwd文件;
- grep /bin/bash ——> 提取所有包含有/bin/bash的行(只有普通用户的权限才是/bin/bash,所有系统用户的权限都是/sbin/nilogin);
- grep -v root ——> 取反,在这个命令里面提取不包含有root的行;
- cut -d “:” -f 1 ——>一冒号[ : ]为分割符提取第一列;
[root@root ~]# useradd user1
[root@root ~]# useradd user2
[root@root ~]# useradd user3
#添加普通用户
[root@root ~]# cat /etc/passwd
#通过cat命令读取/etc下的passwd文档
#在/etc/passwd文档内容如下:
... ...
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
tcpdump:x:72:72::/:/sbin/nologin
user1:x:500:500::/home/user1:/bin/bash
user2:x:501:501::/home/user2:/bin/bash
user3:x:502:502::/home/user3:/bin/bash
[root@root ~]# cat /etc/passwd | grep /bin/bash
root:x:0:0:root:/root:/bin/bash
user1:x:500:500::/home/user1:/bin/bash
user2:x:501:501::/home/user2:/bin/bash
user3:x:502:502::/home/user3:/bin/bash
#grep /bin/bash ——> 提取所有包含有/bin/bash的行(只有普通用户的权限才是/bin/bash,所有系统用户的权限都是/sbin/nilogin);
[root@root ~]# cat /etc/passwd | grep /bin/bash | grep -v root
user1:x:500:500::/home/user1:/bin/bash
user2:x:501:501::/home/user2:/bin/bash
user3:x:502:502::/home/user3:/bin/bash
#grep -v root ——> 取反,在这个命令里面提取不包含有root的行;
[root@root ~]# cat /etc/passwd | grep /bin/bash | grep -v root | cut -d ":" -f 1
user1
user2
user3
#cut -d ":" -f 1 ——>一冒号[ : ]为分割符提取第一列;
#接下来把这个值赋给变量,就可以通过循环删除这些用户了的;
- 如果以空格作为分隔符,cut命令是不能识别的,这是cut命令最大的问题。这时候只能用awk命令。能用cut命令尽量用cut命令,,这个比较简单。
- cut命令只能识别制表符(Tab键),要么就是有分隔符的具体符号,比如,[: , .]都是可以的。
[root@localhost ~]# df -h | cut -d " " -f 1,3
注意:df命令是查看我们分区的使用状况;
示例如下:
[root@root ~]# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/sda2 20G 3.6G 15G 20% /
tmpfs 932M 224K 932M 1% /dev/shm
/dev/sda1 985M 46M 889M 5% /boot
/dev/sda3 9.7G 151M 9.0G 2% /home
/dev/sda5 4.9G 138M 4.5G 3% /opt
/dev/sr0 3.6G 3.6G 0 100% /media/RHEL_6.5 x86_64 Disc 1
写一个脚本,用于判断根分区的使用率,如果这个使用率超过80%,让程序报警,告诉管理员硬盘快占满了,需要管理员手工清除。
严格来讲printf命令并不是字符提取命令,而是应用到awk列提取命令当中的标准输出格式。因此我们学习awk命令之前先学习一下printf命令。
格式:printf ‘输出类型输出格式’ 输出内容
只有加了单元号或双引号,程序才知道不是输出的字符串,而是需要格式化调整的格式符。
输出类型:
- %ns : 输出字符串。n是数字指代输出几个字符;
- %ni : 输出整数。n是数字指代输出几个数字;
- %m.nf : 输出浮点数。m和n是数字,指代输出整数,位数和小数位数。如%8.2f代表共输出8位数,其中2位是小数,6位是整数;
基本格式命令:[root@root ~]# printf ‘%s %s %s\n’ 1 2 3 4 5 6
- ‘%s %s %s\n’ ——> 格式符应该用引号括起来,然后指定我要输出的无内容,如果我们要输出6个字符作为一行,我们就应该写6个%s,如果只写了3个%s系统就认为每3个为一组的形式输出,最后通过\n、\r、\t 来调整输出格式。
其中,\n、\r、\t 这三个格式是最常用的;
示例如下:
输出选项和输出类型并没有用引号括起来的
[root@root ~]# printf %s 1 2 3 4 5 6
123456[root@root ~]#
#输出选项和输出类型并没有用引号括起来的。它会将123456当成一个完整的字符串输出,
#而且没有任何的格式调整,全部都握在了一起。这就是printf最基本的用法。
[root@root ~]# printf %s %s %s 1 2 3 4 5 6
%s%s123456[root@root ~]#
#目的:我想把123当成单独的字符串,456也当成单独的字符串输出。
#实际结果:只有把第一个%s当成了输出选项,后面的所有的内容,包括两个%s被当成了字符串,然后原封不动的输出这不符合我们的需求。
#只有加了单元号或双引号,程序才知道输出的%s不是字符串,而是需要格式化调整的格式符。
[root@root ~]# printf '%s %s %s' 1 2 3 4 5 6
1 2 34 5 6[root@root ~]#
#尝试着将123和456分成两组输出,只是没有换行,因为没有换行符。%s之间有空格,程序就知道输出的时候有空格了。怎么让程序知道123是一组,456是一组呢?这时候就要加入换行符来区分。
#只有加了单元号或双引号,程序才知道输出的%s不是字符串,而是需要格式化调整的格式符。
[root@root ~]# printf '%s %s %s\n' 1 2 3 4 5 6
1 2 3
4 5 6
[root@root ~]# cat student.txt
ID Name gender Mark
1 Liming M 86
2 SC M 90
3 Gao M 83
[root@root ~]# printf '%s' student.txt
student.txt[root@root ~]#
#printf命令这时候输出的并不是文件的内容而是文件名,因为printf命令认为student.txt是输出的字符串。
student.txt[root@root ~]# cat student.txt | printf '%s'
[root@root ~]#
#printf命令后面不能直接加文件名,也不能通过管道符来接收第一条命令的执行结果。
[root@root ~]# printf '%s' $(cat student.txt)
IDNamegenderMark1LimingM862SCM903GaoM83[root@root ~]#
# $(cat student.txt)代表我后面执行的内容是一条系统命令 ,先让这一条命令执行,然后通过printf格式化打印这条命令。当然没有调整格式,所以输出是一连串的字符串。
[root@root ~]# printf '%s\t %s\t %s\t %s\n' $(cat student.txt)
ID Name gender Mark
1 Liming M 86
2 SC M 90
3 Gao M 83
在awk命令的输出中支持print和printf命令:
# awk ‘条件1{动作1} 条件2{动作2} …’ 文件名
条件(Pattern):
- 一般使用关系表达式作为条件
- x > 10 : 判断变量x是否大于10
- x > 10 : 大于等于
- x > 10 : 小于等于
动作(Action):
- 格式化输出。输出某一个内容,
- 流程控制语句。if,for
关于awk命令说明:
- 如果符合条件1,就执行动作1;同理,如果符合条件2,就执行动作2。如果没有定义条件,表示不论什么样的数据都执行这个动作,相当于执行文件当中的所有内容。
- awk命令虽然是列命令,但是它处理数据的时候先读入一行数据,然后把这一行所有的数据都赋给$1($1代表第一列)、$2($2代表第二列)、$3($3代表第三列)…,$0($0代表整个行本身,这一行的所有数据)。然后在判断条件是否符合(这里没有输入任何条件,表示只要数据全部执行这个动作)。
#student.txt文件内容如下:
[root@root ~]# cat student.txt
ID Name gender PHP Linux MySQL Average
1 Liming M 82 95 86 87.66
2 SC M 74 96 87 85.66
3 Gao M 99 83 93 91.66
[root@root ~]# awk '{printf $2 $6}' student.txt
NameMySQLLiming86SC87Gao93[root@root ~]# awk '{printf $2 "\t" $6"\n"}' student.txt
Name MySQL
Liming 86
SC 87
Gao 93
#如果没有定义条件,表示不论什么样的数据都执行这个动作,相当于执行{ }里面文件中的所有内容。
#$2代表文件的第二列,$6代表文件的第六列。这里面printf命令再也不是系统命令,而是awk命令里面的动作命令。
#awk命令虽然是列命令,但是它处理数据的时候先读入一行数据,然后把这一行所有的数据都赋
#给$1($1代表第一列)、$2($2代表第二列)、$3($3代表第二列)...,$0($1代表整个行本身,
#这一行的所有数据)。然后在判断条件是否符合(这里没有输入任何条件,表示只要数据全部执行这
#个动作),我们看到了这个时候先输出$2和$6,这个时候回打印第一行的Name和Average。接着把
#第二行数据读入到awk当中。后面的一次类推。
[root@root ~]# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/sda2 20G 3.6G 15G 20% /
tmpfs 932M 76K 932M 1% /dev/shm
/dev/sda1 985M 46M 889M 5% /boot
/dev/sda3 9.7G 151M 9.0G 2% /home
/dev/sda5 4.9G 138M 4.5G 3% /opt
/dev/sr0 3.6G 3.6G 0 100% /media/RHEL_6.5 x86_64 Disc 1
[root@root ~]# df -h | awk '{print $1 "\t" $5 "\t" $6}'
Filesystem Use% Mounted
/dev/sda2 20% /
tmpfs 1% /dev/shm
/dev/sda1 5% /boot
/dev/sda3 2% /home
/dev/sda5 3% /opt
/dev/sr0 100% /media/RHEL_6.5
[root@root ~]# df -h | awk '{printf $1 "\t" $5 "\t" $6 "\n"}'
Filesystem Use% Mounted
/dev/sda2 20% /
tmpfs 1% /dev/shm
/dev/sda1 5% /boot
/dev/sda3 2% /home
/dev/sda5 3% /opt
/dev/sr0 100% /media/RHEL_6.5
print和printf的区别:
- 在系统Linux命令当中,是没有print命令的,只有printf命令。但是在awk命令当中print命令和printf命令都可以使用;
- 区别就是:printf命令在不会在每行末尾自动加入换行符,需要手工来加入换行符。而print命令会在每行末尾自动加入换行符
[root@root ~]# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/sda2 20G 3.6G 15G 20% /
tmpfs 932M 224K 932M 1% /dev/shm
/dev/sda1 985M 46M 889M 5% /boot
/dev/sda3 9.7G 151M 9.0G 2% /home
/dev/sda5 4.9G 138M 4.5G 3% /opt
/dev/sr0 3.6G 3.6G 0 100% /media/RHEL_6.5 x86_64 Disc 1
[root@root ~]# df -h | grep sda2
/dev/sda2 20G 3.6G 15G 20% /
[root@root ~]# df -h | grep sda2 | awk '{print $5}'
20%
[root@root ~]# df -h | grep sda2 | awk '{print $5}' | cut -d "%" -f 1
20
# awk ‘BEGIN {printf “This is a transcript \n” } {printf $2 “\t” $6 “\n”}’ student.txt
关于BEGIN命令的相关解释:
- BEGIN是指,在所有的数据读取之前,执行{printf “This is a transcript \n” } 的内容,并且{printf “This is a transcript \n” }只执行一次。
- BEGIN是写在了大括号前的,所以BEGIN是一个条件,只有满足了BEGIN条件,才会执行 {printf “This is a transcript \n” } 里面的动作,接着处理后面的数据。
示例如下:
[root@root ~]# awk 'BEGIN{print "test !"} {print $2 "\t" $5}' student.txt
test !
Name Linux
Liming 95
SC 96
Gao 83
# cat /etc/passwd | grep “/bin/bash” | awk ‘BEGIN {FS=":"} {printf $1 “\t” $3 “\n”}’
FS内置变量的作用是:指定分隔符,默认的分隔符是空格和制表符(Tab键)。
FS内置变量,示例如下:
[root@root ~]# awk '{FS=":"} {print $1 "\t" $3}' /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin 1
daemon 2
adm 3
... ...
#但是第一行没有处理的,从第二行开始处理。
#awk命令先执行的时候,先读入“root:x:0:0:root:/root:/bin/bash ”数据,然后在执行后面的操作。
#在执行{FS=":"} 分隔符之前,第一行的数据已经读入,因此这个数据的处理已经来不及了。因此,在FS执行之前加入BEGIN变量。
[root@root ~]# awk 'BEGIN{FS=":"} {print $1 "\t" $3}' /etc/passwd
root 0
bin 1
daemon 2
adm 3
lp 4
#在FS执行之前加入BEGIN变量。在读取第一条数据之前,先先把分隔符写进去,接着处理后面的数据。这样所有的数据都按照我们的要求执行了。
# awk ‘END{printf “The End \n” } {printf $2 “\t” $6 “\n”}’ student.txt
END命令是指当所有的命令都执行完之后,在执行END后面的动作。
示例如下:
[root@root ~]# awk 'BEGIN{FS=":"} END{print"AAAAAAAAAAAAAAAAA"} {print $1 "\t" $3}' /etc/passwd
... ...
tcpdump 72
user1 500
user2 501
user3 502
AAAAAAAAAAAAAAAAA
#所有的命令处理完之后,会执行一条END命令。
# cat student.txt | grep -v Name | \awk ‘$6>=87{printf “\n”}’
示例如下:
[root@root ~]# cat student.txt
ID Name gender PHP Linux MySQL Average
1 Liming M 82 95 86 87.66
2 SC M 74 96 87 85.66
3 Gao M 99 83 93 91.66
[root@root ~]# cat student.txt | grep -v Name | awk '$6 >= 87{printf $2 "\n"}'
SC
Gao
#[ grep -v Name]反选取消“ID Name gender PHP Linux MySQL Average”行。
#在执行{printf $2 "\n"}内容之前,先判断$6 >= 87知否成立。
前面三个命令(cut、printf、awk)都是字段截取的。grep命令是进行行截取的,而cut命令和awk命令是进行列截取。
sed命令是一种几乎包括所有UNIX(包括Linux)的轻量级流编辑器。sed主要是对文本或者是文件当中的数据进行选取、替换、删除、新增命令。相当于一个编译器
[root@localhost ~]# sed [选项] ‘[动作]’ 文件名
- -n : 一般sed命令会把所有数据都输出到屏幕。如果加入此选择,则只会把经过sed 命令处理的行输出到屏幕。
- -e : 允许输入数据应用多条sed命令编辑。
- -i : 用sed的修改结果直接修改读取数据文件(不但进行修改,而且把修改的结果保存到文件当中),而不是由屏幕输出。
关于以上选项的解释:
- 选项-i,不但进行修改而且把修改的结果保存到文件当中。也就说不加-i,你的数据只是输出的时候进行了改变,但是不会影响原文件里面的数据。如果加了-i,不但输出数据进行了更改,你的源文件数据也会进行更改。
- 一般情况下,要用p动作(即,打印输出动作)都要跟-n联合使用,否则,会全部打印。
[root@localhost ~]# sed ‘2p’ student.txt
#查看文件第二行
[root@localhost ~]# sed -n ‘2p’ student.txt
[root@localhost ~]# sed ‘2,4d’ student.txt
#删除第二行到第四行的数据,但不修改文件本身
[root@root ~]# sed '2p' student.txt
ID Name gender PHP Linux MySQL Average
1 Liming M 82 95 86 87.66
1 Liming M 82 95 86 87.66
2 SC M 74 96 87 85.66
3 Gao M 99 83 93 91.66
[root@root ~]# sed -n '2p' student.txt
1 Liming M 82 95 86 87.66
#注意以上命令的输出都不会影响文件的本身,sed命令只要不加-i选项,所有的操作都不影响文件本身。只是影响了屏幕输出。
[root@root ~]# df -h |sed -n '2p'
/dev/sda2 20G 3.6G 15G 20% /
#sed命令可以放在管道符之后处理,接收前一个命令的执行结果。vi就做不到这一点。
[root@root ~]# sed '2,4d' student.txt
ID Name gender PHP Linux MySQL Average
[root@root ~]# sed '2,3d' student.txt
ID Name gender PHP Linux MySQL Average
3 Gao M 99 83 93 91.66
[root@root ~]# cat student.txt
ID Name gender PHP Linux MySQL Average
1 Liming M 82 95 86 87.66
2 SC M 74 96 87 85.66
3 Gao M 99 83 93 91.66
#但是文件的内容并没有更改。没有加i选项,仅仅影响的是屏幕输出。
(2)示例说明:追加、插入
[root@localhost ~]# sed ‘2a hello’ student.txt
#在第二行后追加hello
[root@localhost ~]# sed ‘2i hello
world’ student.txt
#在第二行前插入两行数据。其中\表示数据内有输完,还有第二行
[root@root ~]# sed '2a zuobi' student.txt
ID Name gender PHP Linux MySQL Average
1 Liming M 82 95 86 87.66
zuobi
2 SC M 74 96 87 85.66
3 Gao M 99 83 93 91.66
[root@root ~]# sed '2i canglaoshi \
> bolaoshi' student.txt
ID Name gender PHP Linux MySQL Average
canglaoshi
bolaoshi
1 Liming M 82 95 86 87.66
2 SC M 74 96 87 85.66
3 Gao M 99 83 93 91.66
#和上面一样。修改只是命令的输出,没有修改原文件。
(3)示例说明:行替换
[root@localhost ~]# sed ‘2c No such person’ student.txt
#数据替换。动作c是替换整个行。
[root@root ~]# cat student.txt
ID Name gender PHP Linux MySQL Average
1 Liming M 82 95 86 87.66
2 SC M 74 96 87 85.66
3 Gao M 99 83 93 91.66
[root@root ~]# sed '4c No such person' student.txt
ID Name gender PHP Linux MySQL Average
1 Liming M 82 95 86 87.66
2 SC M 74 96 87 85.66
No such person
(4)示例说明:字符串替换
[root@root ~]# sed ‘s/旧字串/新字串/g’ 文件名
例如:
[root@root ~]# sed ‘3s/74/99/g’ student.txt
#在第三行中,把74 换成99
[root@root ~]# [root@root ~]# sed -i ‘3s/74/99/g’ student.txt
#sed操作的数据直接写入文件
[root@root ~]# sed -e ‘s/Liming//g ; s/Gao//g’ student.txt
#同时把“Liming”和“Gao”替换为空
[root@root ~]# cat student.txt
ID Name gender PHP Linux MySQL Average
1 Liming M 82 95 86 87.66
2 SC M 74 96 87 85.66
3 Gao M 99 83 93 91.66
[root@root ~]# sed '3s/74/99/g' student.txt
ID Name gender PHP Linux MySQL Average
1 Liming M 82 95 86 87.66
2 SC M 99 96 87 85.66
3 Gao M 99 83 93 91.66
[root@root ~]# cat student.txt
ID Name gender PHP Linux MySQL Average
1 Liming M 82 95 86 87.66
2 SC M 74 96 87 85.66
3 Gao M 99 83 93 91.66
[root@root ~]# sed -i '3s/74/99/g' student.txt
[root@root ~]# cat student.txt
ID Name gender PHP Linux MySQL Average
1 Liming M 82 95 86 87.66
2 SC M 99 96 87 85.66
3 Gao M 99 83 93 91.66