重複フィールドを持つ行を削除する sed 式の説明

重複フィールドを持つ行を削除する sed 式の説明

私は再帰を使わずにBashで数値セットのすべての非反復置換を生成する方法を研究していますが、この答えがうまくいくことを知っていますが、その理由を知りたいです。

1、2、3という3つの数字があるとしましょう。

次のコマンドは、すべての可能な非反復置換を生成します。

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

引数が集合{1、2、3}中括弧が3回拡張された場合(すべての可能な結果が印刷された場合)、withが何をするのかをprintf理解します。%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

もしそうなら、このコマンドはsedこのパターンから一意でない値をどのように削除しますかregex?実際には、キャプチャされたグループはありませんが、キャプチャされたグループをどのように参照できるかはわかりません。リテラルマッチングのためにパターンに括弧を使用しますか?この実行に関するすべては、コマンドが出るまで私に意味がありましたsed

答え1

デフォルトでは、これはsedのデフォルトの正規表現(BRE)なので、\(.\)任意の1文字を含むキャプチャグループです。その後、.*すべてをスキップし、\1グループが一致するものと一致します。すべてを一致させることができる場合、文字はグループに対して1回、逆参照に対して1回、2回表示されます。

実際、私が間違っていない限り、これは(何らかの理由で)逆参照をサポートしていないため、標準の拡張正規表現では機能しません。逆参照は以下でのみ言及されます。「BREは複数の文字と一致します。」、EREの下ではなく、実際にEREと同じ機能が私のmacOSでは動作しません(\1リテラル数の場合と同じです1)。

$ printf "%s\n" 122 321 | sed -E -e '/(.).*\1/d'
122

ただし、GNUツールはEREでの逆参照をサポートしています。

sort -uここでは必ずしも必要ではないと思います。中括弧拡張の組み合わせは、重複せずにすべての組み合わせを生成する必要があります。)

答え2

最初のステップは\(.\)それを正しく理解することです。デフォルトの正規表現は、再現する必要があるすべての文字をキャプチャするキャプチャグループです\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!      

上記122、明確ではない:式が固定されていないので1左に移動するので、中央は2キャプチャグループと一致\(.\)し、最後は逆2参照と一致します\1.*(正規表現に一致するゼロ文字以上)は文字列に合わせようとするため、この場合は空の文字列に縮小されます。

疑われる場合は試してください。

echo 122 | grep --color=always '\(.\).*\1'

22色だけが塗られているのがわかります。


それを組み合わせる固定正規表現バージョン:

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

今、「左」と「右」のスロットはありません。

     ^\(.\)  .*  \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

このバージョンでは、最初の数字は最後の数字である必要があるため、一致するものは少なくなります。

関連情報