이 sed 명령이 맨 아래에서 세 번째 "and"를 대체하지 않는 이유는 무엇입니까?

이 sed 명령이 맨 아래에서 세 번째 "and"를 대체하지 않는 이유는 무엇입니까?

2020년 5월 26일 업데이트됨

이것이 버그인 것 같아서 버그를 신고했습니다. ID는 #41558입니다.


나는 단지 장난을 치고 있었고 sed다음 연습을 생각해 냈습니다. "and"(하위 문자열이 아닌 단어)의 마지막에서 세 번째 항목을 교체하여 생성합니다.

dog XYZ foo and bar and baz land good

난 이게 효과가 있을 거라고 생각했어

echo 'dog and foo and bar and baz land good' |
    sed -E 's/(.*)\band\b((.*\band\b){2})/\1XYZ\2/'

그러나 실제로는 "and"의 끝에서 두 번째 발생을 대체합니다. 내가 생각할 수 있는 유일한 설명은 그 중 하나에 "토지"가 포함되어 있다는 것인데 , "경계"라는 단어를 \band\b포함시켰으니 그래야 하지 않을까 ?\b

답변1

sed이는 PCRE에서 지원되는 것처럼 둘러보기 등이 지원되지 않기 때문에 수행하기 어렵습니다 . 문자열을 거꾸로 하고 처음부터 세 번째로 나오는 반전된 단어를 바꾼 다음 다시 바꾸는 것이 더 쉬울 것입니다.

$ echo 'dog and foo and bar and baz land good' | rev | sed 's/\<dna\>/XXX/3' | rev
dog XXX foo and bar and baz land good

표현이 작동하지 않는 이유는 버그처럼 보입니다. 역참조는 마치 이전 내용이 전혀 영향을 미치지 않은 것처럼 \3string 인 것으로 보입니다 . baz land\band.*\band\b

주문하다

sed -E 's/(.*)\<and\>((.*\<and\>){2})/\1XYZ\2/'

sedOpenBSD에서 기본으로 올바른 작업을 수행 하는 것 같습니다(사용 \<\>교체 ).\b

sed나는 GNU 또는 GNU에 대한 기존 버그 보고서를 찾지 못했습니다 glibc. 적어도 그것이라도 놀라지 않을 것입니다.관련된도착하다glibc 오류 25322(왜냐하면 아래를 참조하세요).

이 문제를 더 자세히 해결할 수 있습니다.

sed -E 's/(.*)\band\b(.*\band\b.*\band\b)/\1XYZ\2/'

답변2

질문을 하는 것이 좋습니다. 예제를 테스트한 결과 GNU grep, GNU sed동일한 동작이 발생합니다 GNU awk. 아래에 언급된 한 가지 경우를 제외하고.

  • 잘못된 출력:

    $ echo 'cocoa' | sed -nE '/(\bco){2}/p'
    cocoa
    

    sed -nE '/(\<co){2}/p'또한 awk '/(\<co){2}/'잘못된 동작이 있지만 grep -E '(\<co){2}'올바르게 출력이 제공되지 않습니다.

  • 동작이 정확하고 출력이 없습니다.

    $ echo 'cocoa' | sed -nE '/\bco\bco/p'
    
  • it출력 오류: 완전한 단어가 1개만 나옵니다.with

    $ echo 'it line with it here sit too' | sed -E 's/with(.*\bit\b){2}/XYZ/'
    it line XYZ too
    
  • 동작이 정확하며 입력이 수정되지 않았습니다.

    $ echo 'it line with it here sit too' | sed -E 's/with.*\bit\b.*\bit\b/XYZ/'
    it line with it here sit too
    
  • 단어 경계를 변경하면 \<다른 \>문제가 발생합니다.

    이게 맞다수정하지 마세요입력하다:

    $ echo 'it line with it here sit too' | sed -E 's/with(.*\<it\>){2}/XYZ/'
    it line with it here sit too
    

    이것은 입력을 올바르게 수정합니다.

    $ echo 'it line with it here it too' | sed -E 's/with(.*\<it\>){2}/XYZ/'
    it line XYZ too
    

    하지만 입력을 수정할 수는 없습니다.

    $ echo 'it line with it here it too sit' | sed -E 's/with(.*\<it\>){2}/XYZ/'
    it line with it here it too sit
    

또한 문제가 있는 동작은 충돌하는 단어의 시작 부분에 추가 문자가 있는 경우에만 발생합니다. 예를 들어, itsit. 하지만 끝에 문자가 있는 경우에는 그렇지 않습니다. 예를 들어, itsite.item

$ echo 'it line with it here item too' | sed -E 's/with(.*\bit\b){2}/XYZ/'
it line with it here item too
$ echo 'it line with it here it too item' | sed -E 's/with(.*\<it\>){2}/XYZ/'
it line XYZ too item

관련 정보