如何检查程序的stdout是否在文件中?

时间:2016-11-29 01:15:59

标签: bash macos grep

我尝试了很多次并尝试了不同的方法,但似乎无法让它发挥作用。我正在尝试运行python脚本并grep输出以查看它是否包含在文件中,如果不是,我想将其附加到所述文件。

$./scan_network.py 22 192.168.1.1 192.168.1.20 | if ! grep -q - ./results.log; then - >> results.log; fi

据我所知,macOS grep不理解 - 如stdout那样 - >>>不会工作,因为它也不会拿起stdout。我不知道该怎么做。

如前所述,主要目标是针对文件检查脚本的输出,如果在文件中找不到IP地址,则需要附加。

编辑:

results.log目前是一个空文件。 scan_network.py的输出现在为192.168.1.6。当我在另一个网络上运行时,输出将是一个范围示例中的多个地址,即10.234.x.y,其中x和y将是0到255之间的任何数字。

3 个答案:

答案 0 :(得分:3)

一个简单的解决方案是将日志文件和程序输出合并到一个新的日志文件中:

sort -u <(./scan_network.py 22 192.168.1.1 192.168.1.20) results.log > newresults.log

-u标志会导致从输出中删除重复的行,因此您只能获得每行中的一行。

这具有重新排序行的副作用(因此它们按字母顺序排序)。如有必要,可以保留订单,但它会变得更复杂。

使用合理的现代gnu sort,您可以使用“版本号”排序,这将合理地保持IP编号符合逻辑顺序;您可以使用-V标志来执行此操作。或者,您可以使用sort -u -t. -k1,1n -k2,2n -k3,3n -k4,4n ...单独对八位字节进行排序。或者您可以使用词典排序。不要只使用-n进行标准数字排序,因为它只检查第一个八位字节,并且会与-u选项进行不幸的交互,因为两条比较相等的行被认为是重复的。由于数字排序仅考虑数字前缀,因此会有许多错误重复。

答案 1 :(得分:1)

如果您不介意排序和重写日志文件,rici's helpful answer效果很好(请注意,只需使用-V即可获得真正的每组件数字IP-不幸的是,地址排序是不是 macOS上的一个选项。“ [1]

这是一个替代方案,仅按需就地附加到现有日志文件,而无需重新排序现有行

grep -f results.log -xFv <(./scan_network.py 22 192.168.1.1 192.168.1.20) >> results.log

注意:这假定./scan_network.py的输出是基于行的;如果需要,可以转发到tr以转换为基于行的输出。

  • -f将指定文件中的每一行视为单独的搜索字词,其中任何字词的匹配都被视为整体匹配。
  • -x匹配完整的
  • -F执行文字匹配(不会将搜索字词解释为正则表达式)
  • -v仅输出匹配
  • 的行

净效应是./scan_network.py ...中只有results.log已经存在的results.log输出的行被追加到results.log

但请注意,性能可能会受到较大grep的影响,因此从长远来看,rici的方法可能更为可取,特别是如果日志文件不断增长和/或您希望无论如何,日志按IP地址排序。

至于您尝试过的内容

  • GNU和BSD / macOS -都可选择接受grep作为stdin的占位符来接受输入,但请注意,此操作数永远不需要,因为grep默认从stdin读取输入。

  • 相比之下,只有 GNU -接受-f作为选项参数/dev/stdin,即包含要应用的搜索词的文件 BSD / macOS需要一个显式文件名,一个进程替换(如上所述),或者在一个紧要关系中-f来引用stdin。

  • 必须颠倒搜索逻辑:如上面的命令所示,现有日志文件内容必须作为搜索词(传递给./scan_network.py ...)和-v输出必须作为输入,以确定日志文件中已经-)的行。

  • 使用if ...; then - >> results.log表示stdin 标准输出,取决于上下文,仅仅是约定,它只能用作命令参数,因此您尝试使用-引用stdout输出无效,因为grep -q总是被解释为命令名

  • 如果你使用sort,stdout输出按照定义被抑制,所以没有任何东西可以传递(即使你使用过管道)。

[1] macOS(OS X&#39; s)-V 支持sort进行每个组件的版本号排序(也可以应用于IP地址)。即使macOS sort GNU -V,它仍然是古代 - v5.93 macOS 10.12 - 早于scanf的支持。 功能

答案 2 :(得分:0)

假设您的脚本返回单行文本,您可以将输出存储在变量中,然后将grep存储为该字符串。例如:

logfile="results.log"

# save output to a shell variable
str=$(./scan_network.py 22 192.168.1.1 192.168.1.20)

# don't call grep twice for the same pattern    
grep=$(grep -F "$str" "$logfile")

# append if grep results are empty
if [[ -z "$grep" ]]; then
    echo "$grep" >> "$logfile"
fi