前言
我们上节课学了vim文本编辑器,可以以交互的方式去编辑我们的文本,即在vim是打开文本然后通过键盘对其进行插入、删除、替换等,这节课就会大家介绍一下Linux中的文本三剑客,之前在第三课我们已经学习了grep
命令,这节课我们就来学习剩下的两个,sed
与awk
及一些其它命令
sed命令
上面我们学的vim
是采用交互的方式来编辑文本,但sed
不同,它是采用非交互式,我们事先提供给sed
一组规则,然后sed会按照这组规则来处理我们的目标文本
sed
的基本工作流程:
-
每次仅读取一行内容
-
根据提供的规则命令匹配并修改数据(注意,sed 默认不会直接修改源文件数据,而是会将数据复制到缓冲区中,修改也仅限于缓冲区中的数据)
-
将执行结果输出
sed [options] filename
参数 | 含义 |
---|---|
-e script | 后面跟脚本命令,会将该命令添加到已有命令中 |
-f script_file | 后面根一个脚本命令的文件,会将文件中的脚本命令添加到已有命令中 |
-i | 直接修改源文件 |
-n | 默认情况下,sed 会在所有的脚本指定执行完毕后,会自动输出处理后的内容,而该选项会屏蔽启动输出 |
s替换脚本(常用)
我们学过vim
之后再看这个脚本就很好理解了
这里的address
解释一下,在后面出现的所有address
都同理,address
表示操作目标行,可以省略,如果省略则操作所有行,可以只写一个数字表示精确某行,可以用,
分隔2个数字表示一个范围,最后一行可以使用$
来表示
[address]s/pattern/replacement/flags
# pattern 匹配正则
# replacement 替换的内容
# 一个标记,下面会列出
flag标记 | 功能 |
---|---|
n | 在一行中匹配到第几次时才替换,n为任意数字,不写时默认为1 |
g | 对数据中所有匹配内容进行替换 |
w filename | 将缓冲区的结果写到文件 |
p | 打印替换命令所替换的行,通常与 -n 选项一起使用 |
练习:
我们使用如下命令在桌面创建文件
cat <<EOF>1.txt
linux linux python
java golang java
scala linux linux
golang java scala
linux python golang
EOF
- 替换文件每行第2个
linux
为golang
sed -e 's/linux/golang/2' 1.txt
- 替换所有的
linux
为golang
sed -e 's/linux/golang/g' 1.txt
- 替换第1到3行的
linux
为java
并将替换后的文件保存到2.txt中
sed -e '1,3s/linux/java/g' 1.txt > 2.txt
其它
用法 | 功能 |
---|---|
[address]d | 删除某个范围的内容 |
[address]a|i\text | 这里的|表示或者的意思,a表示在指定行的后面插入一行,i命令在指定行的前面插入一行,如果在添加多行内容内需要在每行的结尾处加上\就可以了 |
[address]c\text | 将指定行的所有内容替换成新内容 |
[address]w filename | 将文本中指定行写入指定文件中 |
[address]r filename | 将一个文件的内容插入到目标文件的指定位置 |
练习:
我们使用如下命令将上面的1.txt
拷贝为带行号的2.txt
cat -n 1.txt > 2.txt
- 删除所有行内容
sed 'd' 2.txt
- 删除第3行的内容
sed '3d' 2.txt
- 删除2到4行的内容
sed '2,4d' 2.txt
- 删除第3行到最后一行的内容
sed '3,$d' 2.txt
- 在第3行后加入新文本
new line
sed -e '3a\new line' 2.txt
- 在第3行前加入新文本
new line
sed -e '3i\new line' 2.txt
- 在第4行后加入如下内容
hello
i amd lengwen
bye
sed -e '4a\
> hello \
> i am lengwen \
> bye' 2.txt
- 替换第3行的内容为
replace line
sed -e '3c\replace line' 2.txt
- 将
2.txt
中的1到3行写到3.txt
并屏蔽sed
的输出,然后打印出3.txt
的内容(提示:在shell中可以使用&&
连接多个命令)
sed -n '1,3w 3.txt' 2.txt && cat 3.txt
- 使用如下命令在桌面创建
add.txt
并将add.txt
的内容插入到2.txt
的第4行后
cat <<EOF>add.txt
this is the first line
this is the second line
EOF
sed -e '4r add.txt' 2.txt
打印命令
echo
linux
的 echo
指令与 PHP
的 echo
指令类似,都是用于字符串的输出,向屏幕打印出一句话
echo "text" #这里的引号可以省略,引号中可以引用变量
echo 'text' # 如果不想引用变量可以使用
在linux
中,我们可以使用变量名=变量值
来定义变量,使用$变量量
来使用变量,比如使用如下命令定义name
变量
name=lengwen
使用如下命令使用变量
echo $name
echo "i am $name"
mkdir $name
使用''
打印
echo '$name'
printf
printf
命令如果大家有学过c语言
相信看到这个命令还是会有些熟悉,linux
中的printf
命令与c语言
标准库中的printf()
用法大同小异
printf format-string [arguments...]
# format-string为格式控制字符串,通常会包含占位符
# arguments为参数列表,不定长,其个数为format-string中的占位符的个数
与echo不同的是printf
是不会在字符串结尾添加换行符的,需要我们手动添加\n
,这里的\n
是转义字符换行的意思,如果大家不了解转义字符可以看看百科上对其的解释及转义字符对照表传送门
转义字符对照表
转义字符 | 说明 |
---|---|
\a | 警告字符,通常为ASCII的BEL字符 |
\b | 后退 |
\c | 抑制(不显示)输出结果中任何结尾的换行字符(只在%b格式指示符控制下的参数字符串中有效),而且,任何留在参数里的字符、任何接下来的参数以及任何留在格式字符串中的字符,都被忽略 |
\f | 换页(formfeed) |
\n | 换行 |
\r | 回车 |
\t | 水平制表符 |
\v | 垂直制表符 |
\\ | 一个字面上的反斜杠字符 |
\ddd | 表示1到3位数八进制值的字符。仅在格式字符串中有效 |
\0ddd | 表示1到3位的八进制值字符 |
printf占位符
占位符 | 含义 |
---|---|
%s | 字符串 |
%c | 字符 |
%d | 整数 |
%f | 小数 |
对于占位符我们都可以通过加数字的方式指定其宽度,如%10s
,指定输出宽度为10的字符串,任何字符都会被显示在 10 个字符宽的字符内,如果不足则自动以空格填充,超过也会将内容全部显示出来,如:
printf "%10s" lengwen
这些占位符默认是右对齐的,我们可以通过加-
来实现左对齐
printf "%-10s" lengwen
awk命令
awk
与sed
类似,也是逐行扫描文件做处理,awk
有自己的语法,说其为一个处理文本文件的编程语言也不为过,我们课程主要学习linux
入门,所以就带大家简单认识一下awk
,学习一些awk
的简单使用
awk [options] [script] filename
参数 | 含义 |
---|---|
-F fs | 以fs作为输入的行分隔符,awk默认的分隔符为空格或制表符 |
-f script_file | 从脚本文件中读取awk脚本命令来代替在命令行中直接输入 |
-v var=val | 在执行脚本之前定义变量var并初始化为val |
为了方便我们演示,我们使用如下命令在桌面创建文件score.txt
cat <<EOF>score.txt
小红 60 70 75
小明 80 65 82
小丽 98 95 97
小黄 76 84 89
小文 57 68 59
小李 77 58 86
EOF
awk的脚本命令由两部分组成,分别为匹配规则和执行命令,这里的匹配规则可以是正则,也可以是一个逻辑运算,执行的命令仅对匹配到的行生效,执行命令部分需要写在{}
内
'匹配规则{执行命令}'
打印
awk的命令中打印主要有2个命令,print
和printf
- print:作用同
echo
命令,用于向屏幕打印一句话 - printf:作用同
printf
命令,用指定格式向屏幕打印一句话
在awk中调用命令时可将参数放到()
内,也可将命令名和命令参数用空格隔开
练习:
对上述文件有几个以9结尾的行打印几个ok
awk '/9$/{print "ok"}' score.txt
内建变量
awk中有很多默认的内建变量我们可以直接使用,下面我列出一些比较常用的
变量 | 描述 |
---|---|
$n | 当前记录的第n个字段,字段间由FS分隔 |
$0 | 完整的输入记录 |
NR | 已经读出的记录数,就是行号,从1开始 |
练习:
- 打印出每行第二列的内容和行号
awk '{print NR, $2}' score.txt
- 打印出
大家好,我叫xxx,我的语文成绩为xx
,假设第1列的数字是语文成绩
awk '{printf "大家好,我叫%s,我的语文成绩是%d\n",$1,$2}' score.txt
- 替换
score.txt
中的空格为----
,然后使用----
做分隔符完成上一题
sed 's/ /----/g' score.txt | awk -F '----' '{printf "大家好,我叫%s,我的语文成绩是%d\n",$1,$2}'
运算符
awk中也有一些运算符,就类似一般编程语言中的运算符,这里就不带大家一个个看了,我们用几个例子感受一下
运算符 | 描述 |
---|---|
= += -= *= /= %= ^= **= | 赋值 |
?: | C条件表达式 |
|| | 逻辑或 |
&& | 逻辑与 |
~ 和 !~ | 匹配正则表达式和不匹配正则表达式 |
< <= > >= != == | 关系运算符 |
空格 | 连接 |
+ - | 加,减 |
* / % | 乘,除与求余 |
+ - ! | 加,减和逻辑非 |
^ *** | 求幂 |
++ -- | 字段引用 |
in | 数组成员 |
练习:
- 过滤第3个成绩为优秀的学生名称
awk -vscore=85 '$4>=score{print $1}' score.txt
BEGIN和END关键字
awk 中还可以指定脚本命令的运行时机。默认情况下,awk 会从输入中读取一行文本,然后针对该行的数据执行程序脚本,但有时可能需要在处理数据前运行一些脚本命令,这就需要使用 BEGIN 关键字
和 BEGIN 关键字相对应,END 关键字允许我们指定一些脚本命令,awk 会在读完数据后执行它们
练习:
这次我们就做一个综合一点的练习,使用begin
和end
及前面所学知识将score.txt
文件按如下格式输出,三列数字从左到右分别是语文数学英语
姓名 语文 数学 英语 总分
--------------------------
小红 60 70 75 205
小明 80 65 82 227
小丽 98 95 97 290
小黄 76 84 89 249
小文 57 68 59 184
小李 77 58 86 221
--------------------------
均分 74.7 73.3 81.3 229.3
分析:
- 我们可以看到在输出每行结果之前我们先输出了表头,这里我们可以放到
begin
中完成 - 同理我们可以将最后的均分放到
end
中完成 - 均分怎么求呢?可以先定义变量用于保存各科的部分,然后除上总行数
实践:
这次由于我们的执行命令很长,所以我们可以写到文件中然后用-f
参数指定从文件中获取脚本,在桌面创建calc.awk
文件,在其内部书写如下内容:
BEGIN {
chinese=0
math=0
english=0
printf "姓名 语文 数学 英语 总分\n"
printf "----------------------------\n"
}
{
chinese+=$2
math+=$3
english+=$4
printf "%s %4d %4d %4d %4d\n",$1,$2,$3,$4,$2+$3+$4
}
END{
printf "----------------------------\n"
printf "均分 %2.1f %2.1f %2.1f %2.1f\n",chinese/NR,math/NR,english/NR,(chinese+math+english)/NR
}
然后执行命令
awk -f calc.awk score.txt
小结
今天我们主要学习了linux
中的文本处理,可能对比前面学习的简单命令来说这节课的sed
及awk
较难理解,大家下去可以自己找些文本文件自己用linux
的文本三剑客试着处理下