【问题标题】:sed: print all lines THROUGH the LAST match of pattern A, then print ONLY lines that match pattern Bsed:通过模式 A 的最后一次匹配打印所有行,然后仅打印与模式 B 匹配的行
【发布时间】:2019-04-29 15:34:16
【问题描述】:

尊敬的同事...

我生成了几千行形式的日志文件:

a
b
X
d
X
e
b
g
Y
a
Y
d

例如,我希望脚本的输出通过“^X”的最后一个匹配项打印所有行,然后仅打印“^Y”的匹配项。以上所需的输出:

a
b
X
d
X
Y
Y

“X”将始终出现,但“Y”可能不会出现。如果没有出现“Y”,我相信最后一个“X”将在文件的最后一行。

用“sed”来做这件事是相当困难的,尽管那是我一直在尝试的。我使用“tac”来翻转行顺序,这样我就可以通过“^X”的 FIRST 匹配删除任何与“^Y”不匹配的内容。因为我不使用“-n”,所以在第一次匹配“^X”之后,所有行都会被回显。我只是再次使用“tac”将其翻转并放入文件中。

似乎工作......

tac /path/to/logfile | \
sed -e '1,/^X/ { /^Y/!d }' | \
tac > /output/path/logfile.processed

没有...?

PS:“tac”在所有 Linux 上都通用吗?

【问题讨论】:

  • 两个X 行之间是否有可能存在Y
  • 输入没有X应该输出什么?
  • @kvantour:不。那里不应该有一个“X”,但我相信这个规则是次要的,需要找到最后一个“X”。
  • @EdMorton:输入中总会有一个“X”。谢谢!

标签: shell perl awk sed scripting


【解决方案1】:

没有tac,使用awk的双通道方法

$ awk 'NR==FNR{if(/^X$/) lx=NR; next} FNR<=lx || /^Y$/' file{,}

a
b
X
d
X
Y
Y

标记X 的最后一个索引并打印该索引和其他匹配模式之前的所有内容。

【讨论】:

  • 如果一个平台有“sed”,但没有“awk”,我会感到惊讶。在某些平台上,“awk”和“tac”都在“/usr/bin”中,但“sed”在“/bin”中。我不确定依赖“tac”或“awk”是否风险更大......感谢您的帮助。我喜欢你的简短回答...
  • 如果一个平台是 POSIX,它将有awk
  • @LanceE.T.Compte 依赖 tac 比 awk 风险更大。在过去 35 年左右的时间里,我使用了许多没有 tac 的机器,但没有一台机器没有 awk 的味道。
【解决方案2】:

为避免阅读两次,您可以使用perl

$ perl -0777 -lnE 'say $1 while (/(\A[\s\S]*^X$|^Y$)/gm)' file
a
b
X
d
X
Y
Y

或者,使用sed 和常用实用程序:

$ sed_cmd=$(printf "1,%sp; /^Y/p" $(cat -n file | sed -nE 's/^[[:space:]]*([[:digit:]][[:digit:]]*)[[:space:]]*X/\1/p' | tail -n 1))
$ sed -nE "$sed_cmd" file
# same output

【讨论】:

  • 除了摆脱“tac”之外,您的“sed”在我的基础上有何改进?看来您正在查找最后一场比赛的行号...
  • 也可以使用'.'而不是 \s\S 通过添加 s 修饰符: perl -0777 -nE 'say $1 while (/(^.*^X$|^Y$)/gms)' file
  • 除了去掉“tac”之外,你的“sed”比我的有什么改进?这就是改进。 tac 在非 Linux 平台上并不常见,但我所拥有的 sed 符合 POSIX。确实,带有cat的管道是确定最后一个X的行号
【解决方案3】:

这是一个使用 Perl 的逻辑上更明确的版本。

perl -MList::Util=max -lnE '
    $lines{$.} = $_; 
    eof || next; 
    $last_match = max grep {$lines{$_} =~ /^X/} keys %lines;
    say for @lines{1 .. $last_match};
    say for grep {$_ =~ /^Y/} @lines{$last_match .. $.};
' /path/to/logfile

【讨论】:

  • 我确实发现这种蛮力方法非常易读/可维护。我已经担心可移植性,因为我需要在许多不同风格的 Linux 上运行。 list::util 现在不在 coremodules 中了吗?
  • 是的,List::Util 是一个核心模块。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-21
  • 1970-01-01
相关资源
最近更新 更多