如果找到相同的单词,则命令egrep提取一行

时间:2018-11-02 14:59:11

标签: regex linux bash shell

我将向您显示此命令的输出:

[root@test ~]# df -P -k -t xfs | egrep '*/PATH whichI don't have/*'

运行命令时,输出如下:

[root@test ~]# df -P -k -t xfs | egrep '*/PATH whichI don't have/*'
10.20.30.40:/var/contain/name1  3877121024 215982080 3661138944       6% /fofo
10.20.30.50:/var/beta/name2  3877121024 215982080 3661138944       6% /fofo
10.20.30.40:/var/contain/name2  3877121024 215982080 3661138944       6% /fofo
10.20.30.50:/var/beta/toto  3877121024 215982080 3661138944       6% /fofo
10.20.30.60:/var/alpha/name2  3877121024 215982080 3661138944       6% /fofo

如果仅一次找到相同的路径,我只想从其他不同的行中提取一行。所以我只想从每多行中提取一行。预期输出:

[root@test ~]# df -P -k -t xfs | egrep '*/PATH whichI don't have/*'  
10.20.30.40:/var/contain/name1  3877121024 215982080 3661138944       6% /fofo
10.20.30.50:/var/beta/name2  3877121024 215982080 3661138944       6% /fofo
10.20.30.60:/var/alpha/name2  3877121024 215982080 3661138944       6% /fofo

如果我找到相同的路径,则只想从每多行中提取一行。 IP地址不相同,如果多行包含相同的地址,我希望仅保留一行。希望对您有帮助

谢谢。

2 个答案:

答案 0 :(得分:1)

我认为grep是此工作的错误工具,而Awk是更好的选择(也可以使用Perl或Python,并且无疑也可以使用其他脚本语言)。

您似乎想要每个IP地址的第一条记录,这是日志格式中直到第一个冒号为止的字段。这表明您需要:

awk -F: '!($1 in a) { print; a[$1] = 1 }'

鉴于问题中的输入显示,输出为:

10.20.30.40:/var/contain/name1  3877121024 215982080 3661138944       6% /fofo
10.20.30.50:/var/beta/name2  3877121024 215982080 3661138944       6% /fofo
10.20.30.60:/var/alpha/name2  3877121024 215982080 3661138944       6% /fofo

  

能否请您解释一下命令的作用?

Awk使用可以将字符串作为下标的关联数组。 -F:选项意味着Awk将行分割为冒号处的字段,因此$1是第一个冒号(IP地址)之前的文本,并且(在此示例中)$2是所有第一个冒号之后的文本,而$0是整个输入行。 Awk程序是“模式-动作”对(或“表达式”或“条件”加上“动作”对)的序列。如果明确指定了该操作,则将其括在括号中(如果未指定,则默认为print $0-打印输入行)。如果未指定模式,则等同于匹配所有行。

在此程序中,条件为!($1 in a),它检查$1是否作为下标出现在数组a中;如果未显示下标,则整个表达式的计算结果为true。当条件为真时,将采取措施。进行打印(隐式$0),并将a[$1]设置为1,以便如果再次出现相同的IP地址,则条件将评估为false,从而防止重复IP地址。 / p>

如果要使用最后一个条目而不是第一个条目,则可以使用变体方案,其中每行将保存在数组{ a[$1] = $0 }的正确条目中,然后会有一个{{ 1}}模式在输入完成后运行:END。主题有无尽的变化。


  

如果我想做同样的事情,但基于IP地址后面的单词而不是IP地址( / word / ),该怎么办?

很大程度上取决于您如何定义“单词”(或'/ word /')。为了使生活更轻松,我计划将一个单词视为一组连续的非空白字符。字段分隔符可以是正则表达式,因此我将使用END { for (i in a) print a[i] }来分隔冒号或空格; IP地址后面的单词就是[: ]。脚本几乎没有变化:

$2

由于冒号后面的名称在示例数据中都不同,因此所有5行都出现在输出中。但是,如果您多次在同一文件上运行脚本(在显示的脚本后添加awk -F '[: ]' '!($2 in a) { print; a[$2] = 1 }' ,其中文件data data包含示例输入),则输出中只会得到一行的副本,这令人放心。

答案 1 :(得分:-1)

好吧,假设您只对/ x / y部分感兴趣,我想您可以这样做:

df -P -k -t xfs > tmpFile
cat tmpFile |cut -d: -f2|cut -d/ -f1-3|sort -u > tmpFile2
while read line; do grep $line tmpFile|head -1; done < tmpFile2

对于您上面提供的数据,输出为

10.20.30.40:/var/alpha/name2  3877121024 215982080 3661138944       6% /fofo
10.20.30.40:/var/beta/name2  3877121024 215982080 3661138944       6% /fofo
10.20.30.40:/var/contain/name1  3877121024 215982080 3661138944       6% /fofo

希望这会有所帮助。