【问题标题】:Evaluating command with Awk使用 awk 评估命令
【发布时间】:2011-10-12 14:29:52
【问题描述】:

问题在于:我有不同的 txt 文件,其中为每个到达服务器的恶意软件数据包注册了时间戳和 IP 地址。我想要做的是创建另一个 txt 文件,该文件显示,对于每个 ip,恶意软件数据包第一次到达。

总的来说,我想做这样的事情:

for every  line in file.txt
 if (ip is not present in list.txt)
 copy timestamp and ip in list.txt

我正在使用 awk 来执行此操作。主要问题是“如果 ip 不在 list.txt 中”。 我正在这样做:

 {    a=$( grep -w "$3" list.txt | wc -c );
    if ( a == 0 )
   {
     #copy timestamp and ip in list.txt
   }

(我使用$3,因为ip地址在源文件的第三列)

我不知道如何让 awk 评估 grep 函数。我也尝试过使用反引号,但它没有用。有人可以给我一些提示吗?

我正在像这样的测试文件上测试我的脚本:

10  192.168.1.1
11  192.168.1.2
12  192.165.2.4
13  122.11.22.11    
13  192.168.1.1
13  192.168.1.2
13  122.11.22.11
14  122.11.22.11
15  122.11.22.11
15  122.11.22.144
15  122.11.2.11
15  122.11.22.111

我应该得到的是:

10  192.168.1.1
11  192.168.1.2
12  192.165.2.4
13  122.11.22.11    
15  122.11.22.144
15  122.11.2.11
15  122.11.22.111

感谢您的帮助,我成功地创建了符合我需要的脚本:

awk '
FILENAME == ARGV[1] {
    ip[$2] = 1
    next
}
! ($2 in ip) {
    print $1, $2 >> ARGV[1]
    ip[$2] = 1
}
' list.txt file.txt 

【问题讨论】:

  • 你能简单地给出一些示例数据和你期望的输出吗?

标签: awk backticks evaluate


【解决方案1】:

将问题解释为“如何从 awk 中评估命令的状态?”,只需使用 system。

{ 如果(系统(“cmd”)== 0){ # 命令成功 { }

所以,就你而言,只需这样做:

{ 如果(系统(“grep -w \”“$3”\“list.txt > /dev/null”)== 0){ ... } }

不过,您可能需要重新考虑解决问题的方法。格雷平 每次的计算量都很大,有更好的方法 接近问题。 (例如,将 list.txt 读入一次数组。)

另外,请注意您不需要使用 wc。如果没有,grep 会失败 匹配字符串。使用返回值而不是解析输出。

【讨论】:

  • 或者使用grep-q 选项,而不是详细地将输出重定向到/dev/null。
  • @CharString grep 的“-q”选项不可移植。 grep 的许多实现都会扼杀它。 (这可能是一个有争议的问题,因为我很确定 -w 也是不可移植的,但我认为尽可能避免使用不可移植的功能是一个好习惯。)
  • 嗯,GNU grep 的手册页说“(-q 由 POSIX 指定。)”我同意避免使用不可移植的特性。 edit:它还说“可移植的 shell 脚本应该避免 -q 和 -s”
  • 谢谢,这正是我所需要的。我会试试的,我会告诉你的。我也知道 grepping 不方便但是我有点着急所以我决定用快速的方式(那是因为我不知道
  • awk sintax 非常适合使用数组!)。对不起,我遇到了一些问题!
【解决方案2】:

这会将执行结果保存到变量a中

BEGIN {  } 
{
"grep -w \"$3\" list.txt | wc -c" | getline a
print a
}
END   {}

【讨论】:

  • 你的意思是"grep -w \"" $3 "\" list.txt | wc -c" | getline a
【解决方案3】:

但实际上你想要做的是让 awk 先读取 list.txt 文件,然后用内存中的 list.txt 数据处理另一个文件。这将使您避免为每一行调用system()

我假设 ip 在 list.txt 的第一列。

当您说copy timestamp and ip in list.txt 时,我假设您想将当前 file.txt 行中的一些信息附加到 list.txt 文件中。

awk '
    FILENAME == ARGV[1] {
        ip[$1] = 1
        next
    }
    ! ($3 in ip) {
        print $3, $(whatevever_column_holds_timestamp) >> ARGV[1]
    }
' list.txt file.txt

鉴于您的问题更新的示例文件和简化要求:

awk '! seen[$2]++' filename

将产生您所看到的结果。如果尚未看到 IP,则该 awk 程序将打印该行。

【讨论】:

  • 理论上,这似乎是满足我需求的一个很好的解决方案。我尝试使用它但最后的list.txt是file.txt的副本但我不知道为什么
  • 我对您的文件格式做了一些假设。如果我没有正确的列号,您必须更新。
  • 感谢您的帮助!我不能使用“简化”脚本,因为我需要在多个源文件上运行它。关于您发布的第一个脚本,我实际上已经更改了列号。因此,按照我在更新中发布的 txt 文件:第 3 行 $2,第 6 行 $2,第 7 行变为“打印 $1, $2 ...”。但似乎它不起作用。我明天再试一次,也许我犯了一些愚蠢的错误!
  • 当然可以:如果您只想从许多文件中提取唯一 IP,只需执行 awk '!seen[$2]++' file1 file2 ... > all.uniq;或者,如果您只想从每个文件中提取唯一 IP,那么 for f in file1 file2 ...; do awk '...' "$f" > "$f.uniq"; done
  • 现在我明白了您发布的第一个脚本有什么问题。它在处理 file.txt 之前从 list.txt 创建 ip 数组。相反,它应该在处理文件时更新数组。所以应该在打印行之后放置一个“ip[$2] = 1”行。这样,脚本似乎按我预期的方式工作。非常感谢!
【解决方案4】:

你想使用getline:

BEGIN {
    "date" | getline current_time
     close("date")
     print "Report printed on " current_time
}

这会将date 的输出放入current_time 变量中。你应该可以用你的 grep | 做同样的事情。 wc -l.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-06-07
    • 2013-05-21
    • 2011-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多