管道和grep是什么
我们在用Shell的时候,会用到|,这个是管道,它可以把前一个命令显示出来的结果,直接交给后一个命令继续处理。
而grep是用于找出包含指定模式的行。例如,当我们有一个observations.txt的文本,里面包含的数据是:
1 | station date temp wind precip weather |
当我们用grep 'Beijing' observations.txt时,筛选出来的结果是:
1 | Beijing 2026-08-01 31.2 3.5 0.0 CLEAR |
可以看到我们将所有包含Beijing的行筛选了出来。
当我们用grep 'RAIN' observations.txt时,得到的结果是:
1 | Shanghai 2026-08-01 29.4 4.2 12.5 RAIN |
我们将所有包含RAIN的行筛选了出来。
所以这里我们就能知道了,grep的基本用法就是,从文本中找出包含指定字符串或者模式的行。
grep 功能汇总
-i |
忽略大小写 |
|---|---|
-n |
显示行号 |
-v |
反向匹配 |
-E |
使用扩展正则表达式 |
-c |
直接统计匹配行数 |
-r |
递归搜索目录 |
-l |
只显示匹配的文件名 |
下面展示几个示例。
grep忽略大小写
需要注意的是,grep是默认区分大小写的,RAIN和rain默认是不同的,如果想忽略大小写,可以使用-i,例如grep -i 'rain' observations.txt。
grep同时满足两个条件
如果想同时搜索包含Beijing和RAIN的行,可以使用管道:grep 'Beijing' observations.txt | grep 'RAIN'。我们刚刚提到,管道是**“将前一个命令处理后的结果,交给后一个命令继续处理”**,所以我们现在的处理流程就是:
1 | 原始文件 |
grep显示行号
如果我们想显示grep输出内容对应的行号,我们使用grep -n 'STORM' observations.txt,我们会得到输出:
1 | 5:Beijing 2026-08-02 30.5 6.1 18.2 STORM |
grep 反向筛选
当我们使用grep -v 'CLEAR' observations.txt,得到的结果是排除所有晴天的记录,因为-v是保留不匹配CLEAR的行。另外,当我们使用grep -v '^station' observations.txt时,这里^代表行首,所以它不是排除所有包含station的行,而是排除以station开头的行。
正则表达式
正则表达式需要与Shell通配符来共同学习区分,我们经常使用的Shell通常由Shell (Zsh) 来解释,而正则表达式通常由grep、sed、awk等程序解释。在使用正则表达式时,我们通常加上引号,这是因为,引号的作用是告诉Shell:不要处理这里面的特殊字符,把他们原样交给grep。
我们接下来先来学习几个正则表达式的方法:
行首^和行尾$
我们通过这种方法可以来查找对应行首和行尾的行,例如查找以Beijing开头的行:
1 | grep '^Beijing' observations.txt |
查找以STORM结尾的行:
1 | grep 'STORM$' observations.txt |
同时限制行首和行尾:
1 | grep -E '^Shanghai.*STORM$' observations.txt |
.表示任意单个字符
在正则表达式中,.表示任意一个字符。例如我们在查找时:
1 | grep '2026.08.01' observations.txt |
它能够匹配2026-08-01
所以我们一般如果确实要匹配普通小数点,需要转义\.。
例如筛选包含31.2的行:
1 | grep '31\.2' observations.txt |
如果我们不这样写,而是写成:
1 | grep '31.2' observations.txt |
可能会匹配到:31-2,31A2等。
*表示一个字符重复零次或者多次
举一个简单的例子:A*可以表示空字符串、A、AA、AAA...,而比较常用的.*可以表示任意字符出现零次或者多次。
所以说:
1 | grep -E '^Beijing.*STORM$' observations.txt |
表示Beijing + 中间任意内容 + STORM
其余的我先不写了,使用的时候再查吧,因为懒的写了,这个实际上还是需要多用啊。
awk是什么
当我们需要按行来筛选的时候,使用grep是比较合适的,但当我们需要按列来筛选的话,使用awk就更加方便了。
我们先来拆解一下我们的文件内容,正如本篇博客开始的,我们的文件每一行有六列:
1 | $1 $2 $3 $4 $5 $6 |
我来记录几个比较实用的吧,全部的估计我也记不完,后面慢慢补充。
跳过标题行
在awk中,NR表示当前记录的行号,如果我们要跳过标题行,打印需要的内容的话,可以类似这样写:awk 'NR > 1 {print $1, $3}' observations.txt,这表明,我们跳过第一行开始打印,并且打印第1列和第3列。
按数值筛选
找出温度超过32°C的记录:
1 | awk 'NR > 1 && $3 > 32 {print $1, $2, $3}' observations.txt |
需要注意的是,这里面NR > 1代表跳过标题,&& 代表并且,$3 > 32代表第三列温度大于32。
除此之外,我们还可以学一些新的逻辑方法:在awk中,= 表示赋值,== 表示判断是否相等,|| 表示或者,!= 表示不等于。
需要注意的是,awk应该使用单引号,不要使用双引号。而且,我们的一般写法是:awk '条件 {动作}' 文件,并且&&只能连接条件,不能连接条件和动作。
我们举一个例子,计算总降水量:
1 | awk 'NR > 1 {total += $5} END {print "总降水量:", total, "mm"}' observations.txt |
这里NR > 1是条件,而{total += $5}是动作,用来计算的,awk会对每一行执行:total += $5,但在执行过程中,不会自动显示变量,文件读取完毕后,END才负责输出结果。
好,我们再总结一遍,在使用时,我们用**awk '条件 {动作}' 文件**,需要注意的是:
1 | AWK 程序通常放在单引号里 |
但是实际使用过程中,还是多用多查为好。