중복 필드가 있는 행을 삭제하는 sed 표현식 설명

중복 필드가 있는 행을 삭제하는 sed 표현식 설명

재귀를 사용하지 않고 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

인수가 집합 {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

그렇다면 이 명령은 sed이 패턴에서 고유하지 않은 값을 어떻게 제거 합니까 regex? 실제로 캡처된 그룹이 없는데 캡처된 그룹을 어떻게 참조할 수 있는지 이해가 되지 않습니다. 리터럴 일치를 위해 패턴에 괄호를 사용합니까? 이 실행에 관한 모든 것은 명령이 나올 때까지 나에게 의미가 있었습니다 sed.

답변1

기본적으로 이는 sed의 기본 정규 표현식(BRE)이므로 \(.\)임의의 한 문자를 포함하는 캡처 그룹입니다. 그런 다음 .*모든 것을 건너뛰고 \1그룹이 일치하는 항목과 일치합니다. 모든 것을 일치시킬 수 있다면 문자는 그룹에 대해 한 번, 역참조에 대해 한 번, 두 번 나타납니다.

사실, 제가 착각한 것이 아니라면 이것은 (어떤 이유로든) 역참조를 지원하지 않기 때문에 표준 확장 정규식에서도 작동하지 않습니다. 역참조는 아래에서만 언급됩니다."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. .*(정규식과 일치하는 0개 이상의 문자)는 문자열에 맞추려고 시도하므로 이 경우 빈 문자열로 축소됩니다.

의심된다면 시도해 보세요

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

이 버전에서는 첫 번째 숫자가 마지막 숫자여야 하므로 일치하는 항목이 더 적습니다.

관련 정보