我有这样的文本文件。
2015-11-24 12:59:37.112 128.206.6.136 source
2014-11-24 12:59:36.920 8.8.8.8 source
2014-11-24 14:59:38.112 23.234.22.106 destination
2014-11-24 13:59:37.113 23.234.22.106 source
2014-11-24 12:59:29.047 74.125.198.141 source
2014-12-25 12:59:36.920 74.125.198.148 destination
如果一个特定的 Ip 地址被标记为源和目的地,那么我想将该 Ip 标记为两个都。在本例中,IP 23.234.22.106 既是源也是目标。所以,我想将其标记为两个都。
我想要的输出应该是这样的
2015-11-24 12:59:37.112 128.206.6.136 source
2014-11-24 12:59:36.920 8.8.8.8 source
2014-11-24 14:59:38.112 23.234.22.106 both
2014-11-24 12:59:29.047 74.125.198.141 source
2014-12-25 12:59:36.920 74.125.198.148 destination
这是我尝试过的。
cat input.txt | awk '{print $3}' | sort | uniq | while read line
do
grep $line input.txt | sort -r -k1 | head -1
done
但是,我不明白如何将特定 Ip 标记为两个都如果它是源也是目的地。在本例中为 23.234.22.106。
我该如何使用 awk 来做到这一点?任何对此的帮助将不胜感激。谢谢
答案1
尝试用sed
sed '
N #add next line
s/\([0-9.]\+\)\s\S\+\n.*\s\1\s\S\+$/\1 both/
P #print first line from two
D #remove first line, return to start
' input.txt
[0-9.]\+
一组数字和点\s
空格或制表符\S\+
一组非空格符号\n
新队.*
任何符号\1
括号内组的反向引用\(...\)
$
图案结束
(修改:删除t
命令(tnx 2杰蒂尔) 并在组前添加 \space 以检查完整地址)
答案2
和perl
:
#! /usr/bin/perl
use strict;
my @lines=();
while(<>) {
chomp;
s/#.*//g; # strip comments
s/^\s*|\s*$//g; # strip leading and trailing spaces
next if (/^$/); # skip blank lines
if (! scalar @lines) {
# store the first line of the file in the array
# we can't do anything else yet, so skip to the next line.
push @lines, $_;
next;
} else {
push @lines, $_;
# split both lines into space-separated fields.
my @a = split /\s+/, $lines[0];
my @b = split /\s+/, $lines[1];
# if 3rd fields are the same, change to "both"
if ($a[2] eq $b[2]) {
@lines = map { $_ =~ s/(source|destination)$/both/oi; $_} @lines;
}
}
print $lines[0],"\n";
shift @lines;
}
print $lines[0],"\n";
这里的想法是使用一个数组(@lines
)来保存当前行和上一行。如果两行的第三个字段(perl 数组从零开始)相同,则将字符串“源”或“目标”更改为“两者”。
打印上一行,无论它们是否被更改。然后从数组中删除前一行,以便shift
在下一次循环时,当前行将是前一行。
最后,循环完成后,打印最后一个输入行。
输出:
$ ./swatesh.pl <swatesh.txt
2015-11-24 12:59:37.112 128.206.6.136 source
2014-11-24 12:59:36.920 8.8.8.8 source
2014-11-24 14:59:38.112 23.234.22.106 both
2014-11-24 13:59:37.113 23.234.22.106 both
2014-11-24 12:59:29.047 74.125.198.141 source
2014-12-25 12:59:36.920 74.125.198.148 destination
一些注意事项:
该sed
脚本运行良好,那么为什么您会选择使用它perl
呢?有什么区别?
@Costas 的sed
版本更快,如果您有数百万行要处理,这可能会很重要。
此perl
版本明确检查两行上的字段 3 是否完全相同,而该sed
版本仅检查看起来类似于 IP 地址的模式是否稍后在同一连接的双行中重复(这不一定是问题 -对于您的示例输入,该sed
版本完美地针对您的示例进行了优化)。
该perl
版本可能更容易适应不同的输入。
循环开始处的代码是一段有用的代码,我在许多 Perl 脚本中使用它来跳过空白行并支持#
文本文件中的注释。我经常在脚本中做同样的事情sed
,但是 sed 脚本越长,可读性就越差......而且我喜欢编写在 6 个月的时间内一眼就能理解的代码。
除了这些相对较小的细节之外,两个脚本都使用非常相似的算法。