이 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"의 마지막에서 두 번째 항목을 대체합니다. 내가 생각할 수 있는 유일한 설명은 "land"를 의 하나로 포함한다는 것인데 \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/'

OpenBSD에서 네이티브( 및 대신 sed사용 ) 로 올바른 작업을 수행하는 것 같습니다 .\<\>\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. 하지만 끝에 문자가 있는 경우에는 그렇지 않습니다. 예를 들어, itsiteitem.

$ 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

관련 정보