尊敬的同事...
我生成几千行格式的日志文件:
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上都普遍可用?
答案 0 :(得分:4)
没有tac
的情况下,使用awk
的双程方法
$ awk 'NR==FNR{if(/^X$/) lx=NR; next} FNR<=lx || /^Y$/' file{,}
a
b
X
d
X
Y
Y
标记X
的最后一个索引,并在该索引和其他匹配模式之前打印所有内容。
答案 1 :(得分: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
答案 2 :(得分:0)
这是使用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