【问题标题】:Find the last occurrence of string and print everything beneath sed awk grep In BASH查找最后一次出现的字符串并打印 sed awk grep In BASH 下的所有内容
【发布时间】:2017-06-20 22:40:13
【问题描述】:

您好,我有一个不断快速更新的大文件。它存储了大量的 FIX-ORDER 消息。每个订单都包含在以单词“FIXES”开头并以单词“Committed”结尾的部分中。在每个订单部分中,修复消息位于第一部分,其他消息位于第二部分。 请参阅下面的输入示例和输出示例。

简而言之,我喜欢 grep 文件并逐行打印最后一个订单部分 并确保修复消息也打印在单独的行上。请参阅下面的第二部分,这是我需要的最终输出。

如果你能帮忙,请告诉我

订单部分的起始文本(我们称之为 orderA)

FIXES LIMIT CHECK ON:

修复消息部分

FIXES LIMIT CHECK ON: 8=FIX.4.2;9=0;35=D;10=100; (Client.123.600)

修复消息部分 + 其余日志消息,直到我们到达单词 Commit 请注意每一行都以右括号结束

FIXES LIMIT CHECK ON: 8=FIX.4.2;9=0;35=D;10=100; (Client.123.600)
1234  abcdefg EFG/HIT [12355] debug JUN 20 17:25:34 Matched  (Match.c.t)
1235  cdghhhh ggg/HIT [19889] INFO JUN 20 17:25:34 Matched  (Found.c.t)
1236  abwwwfg EFG/HIT [12885] debug JUN 20 17:25:34 Matched  (Match.c.t)
Committed 

如果可能的话,我喜欢只使用一个命令行来做些什么;输出有两部分。请在回答之前阅读这两部分:

第一部分)我喜欢使用一个命令来从以“FIXES LIMIT CHECK ON:”开头的行到“提交”一词的每个订单部分,所以基本上

FIXES LIMIT CHECK ON: 8=FIX.4.2;9=0;35=D;10=100; (Client.123.600)
1234  abcdefg EFG/HIT [12355] debug JUN 20 17:25:34 Matched  (Match.c.t)
1235  cdghhhh ggg/HIT [19889] INFO JUN 20 17:25:34 Matched  (Found.c.t)
1234  abcdefg EFG/HIT [12355] debug JUN 20 17:25:34 Matched  (Match.c.t)
Committed 

第二部分)

 I like to print each Fix message that is divided by ";" in a new line 
 please note that the last entry of the fix message is (Client.123.600)
 so my final out put should look like this

FIXES LIMIT CHECK ON: 
8=FIX.4.2;
9=0;35=D;
10=100; 
(Client.123.600)
1234  abcdefg EFG/HIT [12355] debug JUN 20 17:25:34 Matched  (Match.c.t)
1235  cdghhhh ggg/HIT [19889] INFO JUN 20 17:25:34 Matched  (Found.c.t)
1234  abcdefg EFG/HIT [12355] debug JUN 20 17:25:34 Matched  (Match.c.t)
Committed 

【问题讨论】:

  • 您在问题中有很多 orders 却没有显示出完整的输入样本,而且您自己的努力也没有解决它
  • 祝你有美好的一天!!

标签: linux bash awk sed grep


【解决方案1】:

修改如下:

tac <data_file> | sed -n -e '/Committed/,/FIXES LIMIT CHECK ON/p ; /FIXES LIMIT CHECK ON/q' | tac | sed -e '/Client/ { s/:\s?/:\n/g ; s/;\s*/;\n/g }'

【讨论】:

  • 此命令部分有效。它打印输出两次?不知道为什么?我还需要查找最后一次出现的 FIXES?不确定您的脚本是如何做到的?它似乎在寻找文件中的第一个?
  • 嗨,Ed .. 我试了又试,还是一样。它会打印两次结果.. 不知道为什么.. 让我知道您是否可以提供一些输入,如果您有时间详细解释该命令,我可以自己弄清楚吗?
  • 我能够得到最后一次出现的输出,所以现在剩下要做的就是将修复消息分成不同的行
  • 我没有意识到你只想要最后一次出现。对不起,错过了那个。我已经修改了它;虽然不是很漂亮。试试看,让我知道。
【解决方案2】:
$ last_entry_line=$(grep -n '^FIXES ' test.txt | tail -1 | cut -d: -f1 )
$ cat test.txt | sed -n "${last_entry_line},/Committ/p" | sed '/^FIXES/s/\([:;]\)\s*/\1;\n/g'

为了让批评者高兴,我会解释一下。

在第一个命令中,grep -n '^FIXES ' 查找所有以 'FIXES' 开头的行并给我们行号,tail -1 部分只给我们最后一个,cut -d: -f1 解析出行号.

在第二个命令中,sed -n 不打印任何内容,除非我们向其发送“打印”命令。我们的“打印”命令告诉sed 从我们找到的行号打印到“已提交”的下一个实例。我们将这些行发送到另一个 sed,它将冒号和分号(后跟任意数量的空格)替换为冒号或分号(无论我们找到哪个)和一个换行符。

【讨论】:

  • 解释总是有助于增加任何答案的长期价值。
  • 您好,谢谢您的回复。该命令不起作用。我什至逐部分尝试,文件很大并且包含许多条目。我需要获取文件中的最后一个条目,您的命令没有考虑到该条目?除非我错了,否则它会寻找第一次出现的修复?我错了吗,请告诉我?同样,不确定为什么命令的第一部分不起作用?我的意思是 sed -n '/^FIXES/,/Committ/p'
  • 很抱歉——错过了“最后一个条目”部分。将修复答案。
  • 非常感谢 Jack,期待看到修改后的内容
  • 会试一试。我正在尝试寻找可以执行相同操作的 tac 命令,但到目前为止它不起作用。我告诉你
【解决方案3】:

使用 GNU awk 进行 gensub():

$ cat tst.awk
inMsgs {
    # Previous line must have been a FIXES.. line and we are
    # now in the messages lines so just append each of them
    # to the msgs variable as they are read.
    msgs = msgs $0 ORS
}
/Committed/ {
    # Found a "Committed" line so this is the end of a complete
    # block of input so save the contents of the current "fix"
    # and "msgs" variables to the "last read block" equivalents
    # and clear the "in messages block" flag.
    lastFix  = fix
    lastMsgs = msgs
    inMsgs   = 0
}
/^FIXES LIMIT CHECK ON:/ {
    # Found a FIXES... line so save that "fix" line, empty
    # the buffer of "msgs" and set the "in messages block flag"
    # so it is set when the next line is read.
    fix      = $0
    msgs     = ""
    inMsgs   = 1
}
END {
    # We have reached the end of the input file so insert newlines
    # where appropriate in the "lastFix" line then print it and
    # then print the lines stored in the "lastMsgs" variable.
    print gensub(/([^:]+:) ([^;]+;)([^;]+;)([^;]+;)([^;]+;) (.*)/,"\\1\n\\2\n\\3\n\\4\n\\5\n\\6",1,lastFix)
    printf "%s", lastMsgs
}

.

$ awk -f tst.awk file
FIXES LIMIT CHECK ON:
8=FIX.4.2;
9=0;
35=D;
10=100;
(Client.123.600)
1234  abcdefg EFG/HIT [12355] debug JUN 20 17:25:34 Matched  (Match.c.t)
1235  cdghhhh ggg/HIT [19889] INFO JUN 20 17:25:34 Matched  (Found.c.t)
1236  abwwwfg EFG/HIT [12885] debug JUN 20 17:25:34 Matched  (Match.c.t)
Committed

大部分复杂性是确保它只打印最后一个完整记录(即以“已提交”结尾的记录)。

这里有一个更好的示例输入文件来说明为什么上述逻辑是必要的:

$ cat file
stuff
FIXES LIMIT CHECK ON: 8=FIX.4.2;9=0;35=D;10=100; (Client.123.600)
1231  abcdefg EFG/HIT [12355] debug JUN 20 17:25:34 Matched  (Match.c.t)
1232  cdghhhh ggg/HIT [19889] INFO JUN 20 17:25:34 Matched  (Found.c.t)
1233  abwwwfg EFG/HIT [12885] debug JUN 20 17:25:34 Matched  (Match.c.t)
Committed
foo
FIXES LIMIT CHECK ON: 8=FIX.4.2;9=0;35=D;10=100; (Client.123.600)
1234  abcdefg EFG/HIT [12355] debug JUN 20 17:25:34 Matched  (Match.c.t)
1235  cdghhhh ggg/HIT [19889] INFO JUN 20 17:25:34 Matched  (Found.c.t)
1236  abwwwfg EFG/HIT [12885] debug JUN 20 17:25:34 Matched  (Match.c.t)
Committed
bar
FIXES LIMIT CHECK ON: 8=FIX.4.2;9=0;35=D;10=100; (Client.123.600)
1237  abcdefg EFG/HIT [12355] debug JUN 20 17:25:34 Matched  (Match.c.t)
1238  cdghhhh ggg/HIT [19889] INFO JUN 20 17:25:34 Matched  (Found.c.t)
1239  abwwwfg EFG/HIT [12885] debug JUN 20 17:25:34 Matched  (Match.c.t)

在上述情况下,预期输出将是中间块(消息行从 1234、1235 和 1236 开始的那个),而不是最后一个块,因为最后一个块不以 Committed 结尾,所以仍然是在通过生成它的任何命令写入输入文件的过程中。因此,文件中的最后一个 complete 块是中间的块,因此预期的输出与上述 awk 命令产生的一样:

$ awk -f tst.awk file
FIXES LIMIT CHECK ON:
8=FIX.4.2;
9=0;
35=D;
10=100;
(Client.123.600)
1234  abcdefg EFG/HIT [12355] debug JUN 20 17:25:34 Matched  (Match.c.t)
1235  cdghhhh ggg/HIT [19889] INFO JUN 20 17:25:34 Matched  (Found.c.t)
1236  abwwwfg EFG/HIT [12885] debug JUN 20 17:25:34 Matched  (Match.c.t)
Committed

【讨论】:

  • 嗨,Ed .. 我要试一试,Thx,但看起来很复杂,不明白它是如何工作的,
  • 正如我所提到的,只需要打印最后一个完整的块确实会引入一些复杂性,因为您需要确保找到以 FIXES 开头的最后一个文本块,但仅在以下情况下覆盖前一个这样的块当前的以 Committed 结尾,因为这将是文件中的最后一个完整块,即使它后面有 FIXES 行。但是,每个代码段本身都很简单。我添加了更好的示例输入,说明了为什么您需要我发布的代码,并且我在每个代码块中添加了 cmets。鉴于该输入和其他问题,已发布的 sed+other-tools 解决方案将失败
  • @theuniverseisflat 这对你不起作用吗?如果确实如此,请查看stackoverflow.com/help/someone-answers 了解下一步该做什么。
猜你喜欢
  • 2015-06-08
  • 2014-02-15
  • 1970-01-01
  • 2021-02-22
  • 1970-01-01
  • 2013-01-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多