grep 查找不在模式之后的行

grep 查找不在模式之后的行

我试图找到文件中不符合特定模式的所有行。

一段时间以来,我在history使用 GNU bash(版本 4 和 5)时遇到了一个问题,其中命令出现重复。我认为这是因为我.bashrc有以下行:

 PROMPT_COMMAND="history -a; history -n; $PROMPT_COMMAND"

由于我使用终端多路复用器(screen和/或tmux),上述命令会执行多次(因此echo $PROMPT_COMMAND会导致history -a; history -n; history -a; history -n;

在某些情况下(特别是在不同的窗格/窗口/框架/缓冲区上同时执行操作时),我输入的最后一个命令在我的~/.bash_history.这导致了如下条目:

#1596110297
yadm list -a | xargs -t ls -l
yadm list -a | xargs -t ls -l

不用说,这很烦人。 我只是(希望)找到了该问题的解决方案history(通过将命令更改为PROMPT_COMMAND="history -a; history -n)但是 更正:这并没有解决history.

现在我想删除重复的条目。

因此,我目前正在尝试找到一个正则表达式来标记除以 开头的行#及其后一行之外的所有内容。我的第一个想法是结合grep -v(反转选择)和grep -A 1(在匹配模式后额外获得一行)。但

grep -v "^#" -A 1 ~/.bash_history

没有得到我希望的结果。

因此我的问题是:有人知道如何使用 来做到这一点吗grep?如果不是:我如何使用其他工具(sed、、awk...)来完成此任务?

答案1

据我了解,grep -v "^#" -A 1意味着打印不以井号开头的行,并且每行后一行。但你不想要相反的结果吗,打印以下行以井号开始,然后一行?

给定一个测试文件:

#123
echo this
echo this
#456
echo that
echo that
echo that
#789
echo third

grep -A1 ^# history.txt |grep -vxFe --印刷:

#123
echo this
#456
echo that
#789
echo third

第二个grep是去掉组分隔符grep -A打印。

或者uniq history.txt应该只打印每组连续的相同行中的一个。

答案2

使用 Raku(née Perl6)

这似乎是“触发器”操作符的工作,可以在多种脚本语言中使用。以下是使用 Raku 编程语言(以前称为 Perl6)的答案。首先创建一个更广泛的测试文件:

$ cat repeated_log.txt
#1596110297_1
A_yadm list -a | xargs -t ls -l
B_yadm list -a | xargs -t ls -l
#1596110297_2
C_yadm list -a | xargs -t ls -l
D_yadm list -a | xargs -t ls -l
E_yadm list -a | xargs -t ls -l
#1596110297_3
F_yadm list -a | xargs -t ls -l
G_yadm list -a | xargs -t ls -l
H_yadm list -a | xargs -t ls -l
I_yadm list -a | xargs -t ls -l
#1596110297_4
#1596110297_5

fff现在使用 Raku 的触发器运算符来编写一行代码,它实现了“类似 sed”的行为。对于第一个正则表达式看到(在行首^^)文字“#”字符的行,捕获将打开。一旦打开,捕获将忽略第一个正则表达式并根据第二个正则表达式进行计算,当它找到与缺少(在行开头^^)“#”字符的行匹配时关闭。 “负”正则表达式在下面的代码中使用 实现<-[#]>,它是一个负“枚举字符类”,也是 Raku 语言的一个真正功能:

$ raku -ne '.put if /^^ "#" / fff /^^ <-[#]> /;' repeated_log.txt
#1596110297_1
A_yadm list -a | xargs -t ls -l
#1596110297_2
C_yadm list -a | xargs -t ls -l
#1596110297_3
F_yadm list -a | xargs -t ls -l
#1596110297_4
#1596110297_5

实际上,第一个正则表达式(中缀运算符左侧fff)可以使用<+[#]>正“枚举字符类”来编写,以实现更并行的构造:

$ raku -ne '.put if /^^ <+[#]> / fff /^^ <-[#]> /;' repeated_log.txt
#1596110297_1
A_yadm list -a | xargs -t ls -l
#1596110297_2
C_yadm list -a | xargs -t ls -l
#1596110297_3
F_yadm list -a | xargs -t ls -l
#1596110297_4
#1596110297_5

另外,在我看来,您可以通过要求匹配或反对行首“#”后跟一个或多个数字来改进您的正则表达式,即<digit>+,见下文:

$ raku -ne '.put if /^^ <+[#]> <digit>+ / fff /^^ <-[#]> <-digit>+ /;' repeated_log.txt
#1596110297_1
A_yadm list -a | xargs -t ls -l
#1596110297_2
C_yadm list -a | xargs -t ls -l
#1596110297_3
F_yadm list -a | xargs -t ls -l
#1596110297_4
#1596110297_5

[上面的所有代码都会删除以 B、D、E、G、H 和 I 开头的重复行。我注意到的唯一怪癖是两个连续的目标行(例如“#1596110297”)将出现在输出中,但不清楚对我来说,如果您的输入文件将包含这样的连续行]。

https://raku.org/

相关内容