1.cut列提取命令
cut [选项] 文件名
选项:
-f 列号:提取第几列
-d 分隔符:按照指定分隔符分隔列
-c 字符范围:不依赖分隔符来区分列,而是通过字符范围(行首为0)来进行字段提取。“n-”表示从第n个字符到行尾;“n-m”从第n个字符到第m个字符;“-m”表示从第1个字符到第m个字符
cut命令默认分隔符是制表符,也就是“tab”键,不过对空格符支持的不好
2.awk编程
printf格式化输出
printf 输出类型输出格式 输出内容
输出类型 | 含义 |
---|---|
%ns | 输出字符串,n是数字指代输出几个字符 |
%ni | 输出整数,n是数字指代输出几个数字 |
%m.nf | 输出浮点数,m和n是数字,指代输出的整数位数和小数位数。如%8.2f,代表共输出8位数,其中2位是小数,6位是整数 |
输出格式 | 含义 |
---|---|
\a | 输出警告声音 |
\b | 输出退格键,也就是Backspace键 |
\f | 清除屏幕 |
\n | 换行 |
\r | 回车,也就是Enter键 |
\t | 水平输出空格键,也就是Tab键 |
\v | 垂直输出空格键,也就是Tab键 |
如上格式的txt文件,我们按字符串进行输出
如果不指定输出格式,则会把所有输出内容连在一起输出。其实文本的输出本身就是这样的,cat等文本输出命令之所以可以按照格式漂亮的输出,那是因为cat命令已经设定了输出格式。那么为了用printf输出合理的格式,应该这样做:
awk基本使用
awk '条件1{动作1} 条件2{动作2}...' 文件名
条件(Pattern) :
一般使用关系表达式作为条件。这些关系表达式非常多,例如:
x > 10 判断变量x是否大于10
x==y 判断变量x是否等于变量y
A~B 判断字符串A中是否包含能匹配B表达式的子字符串
A!~B 判断字符串A中是否不包含能匹配B表达式的子字符串
动作(Action) :
格式化输出
流程控制语句
我们这里先来学习awk基本用法,也就是只看看格式化输出动作是干什么的。至于条件类型和流程控制语句我们在后面再详细介绍。那看看这个例子吧:
awk '{printf $2 "\t" $6 "\n"}' student.txt
# 输出第二列和第六列
awk的条件
条件的类型 | 条件 | 说明 |
---|---|---|
awk保留字 | BEGIN | 在awk程序一开始时,尚未读取任何数据之前执行。BEGIN后的动作只在程序开始时执行一次 |
END | 在awk程序处理完所有数据,即将结束时执行。END后的动作只在程序开始时执行一次 | |
关系运算符 | > | 大于 |
< | 小于 | |
>= | 大于等于 | |
<= | 小于等于 | |
== | 等于。用于判断两个值是否相等,如果是给变量赋值,请使用“=”号 | |
!= | 不等于 | |
A~B | 判断字符串A中是否包含能匹配B表达式的子字符串 | |
A!~B | 判断字符串A中是否不包含能匹配B表达式的子字符串 | |
正则表达式 | /正则/ | 如果在“//”中可以写入字符,也可以支持正则表达式 |
- BEGIN
BEGIN是awk的保留字,是一种特殊的条件类型。BEGIN的执行时机是“在awk程序一开始时,尚未读取任何数据之前执行”。一旦BEGIN后的动作执行一次,当awk开始从文件中读入数据, BEGIN的条件就不再成立,所以BEGIN定义的动作只能被执行一次。例如:
awk 'BEGIN{printf "This is a transcript \n"} {print $2 "\t" $6 "\n"}' student.txt
#awk命令只要检测不到完整的单引号不会执行,所以这个命令的换行不用加入“\”,就是一行命令
#这里定义了两个动作
#第一个动作使用BEGIN条件,所以会在读入文件数据前打印"This is a transcript"(只会执行一次)
#第二个动作会打印文件的第2列和第6列
- END
END也是awk保留字,不过刚好和BEGIN相反。END是在awk程序处理完所有数据,即将结束时执行。END后的动作只在程序结束时执行一次 - 关系运算符
举几个例子看看关系运算符。假设我想看看平均成绩大于等于87分的学员是谁,就可以这样输入命令:
cat student.txt | grep -v Name | awk '$6 >=87 {printf $2 "\n"}'
#使用cat输出文件内容,用grep取反包含“Name”的行
#判断第六字段(平均成绩)大于等于87分的行,如果判断式成立,则打印第六列(学员名)
加入了条件之后,只有条件成立动作才会执行,如果条件不满足,则动作则不运行。通过这个实验,大家可以发现,虽然awk是列提取命令,但是也要按行来读入的。这个命令的执行过程是这样的:
- 如果有BEGIN条件,则先执行BEGIN定义的动作
- 如果没有 BEGIN条件,则读入第一行,把第一行的数据依次赋予$0、$1、 $2等变量。其中$0
代表此行的整体数据,$1 代表第一字段,$2 代表第二字段 - 依据条件类型判断动作是否执行。如果条件符合,则执行动作,否则读入下一行数据。如果没有条件,则每行都执行动作
- 读入下一行数据,重复执行以上步骤
再举个例子,如果想看看Sc用户的平均成绩呢?
awk '$2~/Sc/ {printf $6 "\n"}' student.txt
#如果第二字段中包含有“Sc”字符,则打印第六段数据
这里要注意在awk中,使用“/ /”包含的字符串,awk命令才会查找。也就是说字符串必须用“/ /”包含,awk命令才能正确识别
awk内置变量
awk内置变量 | 作用 |
---|---|
$0 | 代表目前awk所读入的整行数据。我们已知awk是一行一行读入数据的,$0就代表当前读入行的整行数据 |
$n | 代表目前读入行的第n个字段 |
NF | 当前行拥有的字段(列)总数 |
NR | 当前awk所处理的行,是总数据的第几行 |
FS | 用户定义分隔符。awk默认分隔符是任何空格,如果想要使用其他分隔符(如“:”),就需要FS变量定义 |
ARGC | 命令行参数个数 |
ARGV | 命令行参数数组 |
FNR | 当前文件中的当前记录数(对输入文件起始为1) |
OFMT | 数值的输出格式(默认为%.6g) |
OFS | 输出字段的分隔符(默认为空格) |
ORS | 输出记录分隔符(默认为换行符) |
RS | 输入记录分隔符(默认为换行符) |
cat /etc/passwd | grep "/bin/bash" | awk '{FS=":"} {printf $1 "\t" $3 "\n"}'
# 查询可以登录的用户的用户名和UID
我们发现第一行打印了整行,后面的行正确打印说明第一行没有把冒号作为分隔符打印,这是为什么呢?
awk先把第一行的数据读到awk中,依次赋予$0、$1、 $2等变量,再进行{print}处理,这时才发现分隔符是冒号,这时只能按照默认分隔符为空格的方式打印,但是第一行没空格,所以只能整体打印;到了第二行,先知道分隔符是冒号,所以依次赋予$0、$1、 $2等变量前先按照冒号分割,所以才正确打印,那怎么才能解决这个问题?
cat /etc/passwd | grep "/bin/bash" | awk 'BEGIN {FS=":"} {printf $1 "\t" $3 "\n"}'
#先执行BEGIN,将冒号作为分隔符,再赋值打印
cat /etc/passwd | grep "/bin/bash" | awk 'BEGIN {FS=":"} {printf $1 "\t" $3 "\t 行号:" NR "\t 字段数:" NF "\n"}'
# 开始执行{分隔符是:},{输出第一字段和第三字段,输出行号(NR值),字段数(NF值)}
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 -i '2,4d' student.txt
# 在删除2~4行的同时也操作原始文本数据,是真删除