【问题标题】:grep -E {,1} showing results that have more than 1 occurrencegrep -E {,1} 显示出现超过 1 次的结果
【发布时间】:2018-02-02 06:17:01
【问题描述】:

我一直在试图弄清楚如何 grep 一行只出现 N 个字符。

[root@example DIR]# grep -E "6{,1}" test.txt
6543
6625
6668
6868
6666
1161

我想要的是 grep 打印出以下内容:

[root@example DIR]# grep -E "6{,1}" test.txt
6543
1161

我错过了什么?

【问题讨论】:

  • 我们可以假设所有字符都是十进制数字吗?
  • 基本上你的问题是缺乏锚定。描述整条线,它会起作用。
  • 6666 在不少于四个不同的地方有一个 6 出现,所以显然它被包括在内!
  • @Yunnosch 是的,所有十进制数字
  • 顺便说一句,不要root

标签: regex linux bash grep


【解决方案1】:

使用 awk 我会:

$ awk '/6/&&!/6.*6/' file
6543
1161

它转换为grep,例如:

$ grep 6 file | grep -v 6.*6
6543
1161

编辑:

@Sundeep 使用 6 作为字段分隔符并对字段进行计数的巧妙想法(参见 cmets):

$ awk -F6 'NF==2' file
6543
1161

^他在下面的评论。

【讨论】:

  • 来吧,你不是建议使用6作为字段分隔符的字段数的最简单方法吗? ;)
  • 呵呵,没想到。发表它。 :D
  • 不,很酷,您可以添加它...某处有重复,懒得搜索;)
  • 感谢@JamesBrown 来救援 :)
  • @Allan 只是从此处或 unix.stackexchange 中的其他答案中记住此技术的一个例子...
【解决方案2】:

“我错过了什么”部分是:一旦找到匹配项,正则表达式将忽略尾随上下文,除非您告诉他们不要这样做。所以666 匹配6{,1},因为第一个6 匹配并且你没有说你不想在那之后允许额外的6 实例。

您可以使用更复杂的正则表达式,例如 ^([^6]*6){,1}[^6]*$,但实际上我会使用 Awk 来解决这个问题:

awk -F 6 'NF==2' file

将在file 中查找所有行,其中恰好出现一次6

我们巧妙地使用6 作为字段分隔符,并在 Awk 读取一行并将其拆分为字段时检查字段数。变量NF 方便地告诉我们结果字段的数量。

Awk 程序的格式为condition { action },其中两个部分都是可选的。在没有条件的情况下,{ action } 会出现在每个输入行上。如果没有{ action },则默认操作是打印满足条件的行。这里,条件是NF==2

【讨论】:

    【解决方案3】:

    你需要左右边界,否则后面的匹配可以忽略。

    grep -E "^[^6]*6[^6]*$" *
    

    这意味着:

    • ^ 行首
    • [^6]* 非六分之二,随心所欲
    • 六一六
    • 后跟非六,任意数量
    • $ 行尾。

      grep -E "6{,1}" *

    在模式中的某个位置表示从零到一一六。

    【讨论】:

    • 谢谢。那么你将如何找到 2 次出现的 6?
    • 一个非 6 块,后跟一个 6。 egrep "^[^8]*8[^8]*8[^8]*$"(我的测试数据已经包含 2 个八,但不是六)。好的,接下来的问题是,对于 791 个 6es,或者其中的 14 到 22 个,该怎么办。 :) 然后我会使用 sed,删除每一个非 6,并使用 6{14,22} 表达式,产生行号并在原始文件中查找这些行号。
    • 哦,现在你可以使用分组和花括号了:egrep "^[^8]*(8[^8]*){2}$" *
    【解决方案4】:

    如果你有 GNU grep,那么你可以简单地通过激活 perl 正则表达式模式 -P 并使用正向向后查找并获取除使用 -v 匹配的行之外的每一行

    grep -Pv "(?<=6)[^6]*6" input                                                                                                                
    6543
    1161
    

    如果您没有 GNU grep,那么您将不得不使用管道并分两步完成。

    grep 6 input | grep -vE '6.*6'                                                                                                               
    6543
    1161
    

    【讨论】:

      猜你喜欢
      • 2014-01-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-20
      • 2020-09-25
      • 2021-03-26
      • 2017-02-17
      • 2021-04-12
      相关资源
      最近更新 更多