Grep:仅查找一次匹配未知字符的行

3

我有一个十六进制行的列表,例如:

0b 5a 3f 5a 7d d0 5d e6 2b c4 7e 7d c2 c0 e6 9a 
84 bd aa 74 f3 85 da 9d ac b6 e0 b6 62 0f b5 d5
c0 b0 f5 60 02 8b 1c a4 41 7c 53 f2 85 20 a0 d1
...

我正在尝试使用grep查找所有包含仅出现一次字符的行。

例如:第三行中只有一个'd'。

我尝试了以下方法,但它没有起作用:

egrep '^.*([a-f0-9])[^\1]*$'

你的意思是所有只出现一次字符的行吗?还是指特定字符只出现一次的行?如果是后者,你可以使用egrep '^[^d]d[^d]$'来获取所有只有一个d的行。 - LGenzelis
所有仅包含一个字符的行。 - Thibaut Vermeulen
3个回答

3

这可以通过正则表达式来实现,但必须使用详细模式。
它有点不能泛化。

 # ^(?:[^a]*a[^a]*|[^b]*b[^b]*|[^c]*c[^c]*|[^d]*d[^d]*|[^e]*e[^e]*|[^f]*f[^f]*|[^0]*0[^0]*|[^1]*1[^1]*|[^2]*2[^2]*|[^3]*3[^3]*|[^4]*4[^4]*|[^5]*5[^5]*|[^6]*6[^6]*|[^7]*7[^7]*|[^8]*8[^8]*|[^9]*9[^9]*)$

 ^ 
 (?:
      [^a]* a [^a]* 
   |  [^b]* b [^b]* 
   |  [^c]* c [^c]* 
   |  [^d]* d [^d]* 
   |  [^e]* e [^e]* 
   |  [^f]* f [^f]* 

   |  [^0]* 0 [^0]* 
   |  [^1]* 1 [^1]* 
   |  [^2]* 2 [^2]* 
   |  [^3]* 3 [^3]* 
   |  [^4]* 4 [^4]* 
   |  [^5]* 5 [^5]* 
   |  [^6]* 6 [^6]* 
   |  [^7]* 7 [^7]* 
   |  [^8]* 8 [^8]* 
   |  [^9]* 9 [^9]* 
 )
 $ 

对于发现,如果您在字母和数字周围放置捕获组,并使用分支重置:

 ^ 
 (?|
      [^a]* (a) [^a]* 
   |  [^b]* (b) [^b]* 
   |  [^c]* (c) [^c]* 
   |  [^d]* (d) [^d]* 
   |  [^e]* (e) [^e]* 
   |  [^f]* (f) [^f]* 

   |  [^0]* (0) [^0]* 
   |  [^1]* (1) [^1]* 
   |  [^2]* (2) [^2]* 
   |  [^3]* (3) [^3]* 
   |  [^4]* (4) [^4]* 
   |  [^5]* (5) [^5]* 
   |  [^6]* (6) [^6]* 
   |  [^7]* (7) [^7]* 
   |  [^8]* (8) [^8]* 
   |  [^9]* (9) [^9]* 
 )
 $ 

这是输出结果:
 **  Grp 0 -  ( pos 0 , len 50 ) 
0b 5a 3f 5a 7d d0 5d e6 2b c4 7e 7d c2 c0 e6 9a 

 **  Grp 1 -  ( pos 7 , len 1 ) 
f  

-----------------------

 **  Grp 0 -  ( pos 50 , len 51 ) 

84 bd aa 74 f3 85 da 9d ac b6 e0 b6 62 0f b5 d5

 **  Grp 1 -  ( pos 77 , len 1 ) 
c  

-----------------------

 **  Grp 0 -  ( pos 101 , len 51 ) 

c0 b0 f5 60 02 8b 1c a4 41 7c 53 f2 85 20 a0 d1

 **  Grp 1 -  ( pos 148 , len 1 ) 
d  

我认为这个解决方案不可行。我来自德国,那么 ß 怎么办?我的意思是,这个解决方案对于世界上大多数文本输入数据来说都不起作用,但对于 MAC 地址来说是可以的 ;) - hek2mgl
@hek2mgl - 除了以有限的冗长方式,它并不是真正实用的。它就是它本身。 - user557597
我再次思考了一下... 我认为对于这个普遍问题的答案是:“所有只出现一次字符所在的行。” 只有当字符集限制在正则表达式可处理的范围内时才能解决(我不知道模式长度的限制,但我猜测有一定的限制)。这意味着对于Unicode来说可能会很难。然而,您的答案表明,在有限的字符集下,特别是针对MAC地址作为输入数据时,确实是可能的。最后,我认为这是一个好答案,+1。 - hek2mgl

1

我不知道如何用正则表达式实现它。但是你可以使用这个愚蠢的 awk 脚本:

awk -F '' '{for(i=1;i<=NF;i++){a[$i]++};for(i in a){if(a[i]==1){print;next}}}' input

脚本计算行中每个字符出现的次数。在行末,它检查所有总数,并且如果其中至少一个总数等于1,则打印该行。

0
这是一段使用了许多 shell 工具的代码,超越了 grep。 它逐行读取输入,并生成一个频率表。当找到一个频率为 1 的元素时,它会输出唯一的字符和整行内容。
cat input | while read line ; do 
     export line ; 
     echo $line | grep -o . | sort | uniq -c | \
         awk '/[ ]+1[ ]/ {print $2 ":" ENVIRON["line"] ; exit }' ; 
done

请注意,如果您只对数字感兴趣,可以将 grep -o . 替换为 grep -o "[a-f]"

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接