解释删除重复字段行的sed表达式

Ant*_*yBB 5 sed text-processing regular-expression

我正在研究如何在不使用 Bash 中的递归的情况下生成一组数字的所有非重复排列,我发现这个答案有效,但我想了解原因。

假设您有三个数字:1、2、3。

以下命令将生成所有可能的非重复排列:

printf "%s\n" {1,2,3}{1,2,3}{1,2,3} | sort -u | sed '/\(.\).*\1/d'
123
132
213
231
312
321
Run Code Online (Sandbox Code Playgroud)

我理解当参数是集合 {1, 2, 3} 的大括号扩展三倍时printfwith 的%s作用(这将打印每个可能的结果)。

我知道这sort -u只会输出唯一的行。

我知道这sed /<pattern>/d用于删除任何匹配的行<pattern>

读了里面的模式sed,我有些糊涂了。我知道如何阅读,regex但我没有看到这种模式在sed命令中是如何工作的。

\( = literal '('
.  = any character, once
\) = literal ')'
.* = any character, zero or more times
\1 = reference to first captured group
Run Code Online (Sandbox Code Playgroud)

那么该sed命令如何从此regex模式中删除非唯一值?我不明白如何引用一个被捕获的组,而实际上没有一个?在模式中使用括号进行字面匹配?在sed命令之前,关于这次执行的一切对我来说都是有意义的。

Qua*_*odo 5

作为第一步,您需要\(.\)正确理解。在基本的正则表达式中,它是一个捕获组,捕获任何字符,必须由\1. 这些不是文字括号。


现在,对于非常酷的部分!在每种情况下,正则表达式的每个元素匹配什么?

     Left  \(.\)  .*  \1  Right  Result
111        1      1   1          Deleted!
112        1          1   2      Deleted!
113        1          1   3      Deleted!
121        1      2   1          Deleted!
122  1     2          2          Deleted!
123        ?      ?   ?          NoMatch
131        1      3   1          Deleted!
132        ?      ?   ?          NoMatch
133  1     3          3          Deleted!      
Run Code Online (Sandbox Code Playgroud)

在 上122,如果不清楚:由于表达式未锚定,1向左移动,中间2匹配捕获组\(.\),最后2匹配反向引用\1.*(匹配正则表达式的零个或多个字符)将尽最大努力适应字符串,因此在这种情况下它会收缩为空字符串。

如果您怀疑它,请尝试

echo 122 | grep --color=always '\(.\).*\1'
Run Code Online (Sandbox Code Playgroud)

您将看到只有22已着色的 。


将其与正则表达式的锚定版本进行比较:

$ printf "%s\n" {1,2,3}{1,2,3}{1,2,3} | sort -u | sed '/^\(.\).*\1$/d'
112
113
122
123
132
133
...
Run Code Online (Sandbox Code Playgroud)

现在没有“左”和“右”插槽:

     ^\(.\)  .*  \1$  Result
111  1       1   1    Deleted!
112  ?       ?   ?    NoMatch
113  ?       ?   ?    NoMatch
121  1       2   1    Deleted!
122  ?       ?   ?    NoMatch
123  ?       ?   ?    NoMatch
131  1       3   1    Deleted!
132  ?       ?   ?    NoMatch
133  ?       ?   ?    NoMatch
Run Code Online (Sandbox Code Playgroud)

第一个数字必须是这个版本的最后一个数字,所以匹配的少。