실험 및 예시

실험 및 예시

댓글에서이 문제다양한 sed 구현이 상당히 간단한 프로그램에 대해 의견이 일치하지 않는 상황이 발생하며, 우리(또는 적어도 나는) 사양이 실제로 이에 대해 요구하는 것이 무엇인지 결정할 수 없습니다.

문제는 삭제된 행에서 시작하는 범위의 동작입니다.

1d;1,2d

2번째 줄을 삭제해야 할까요?명령에 도달하기 전에 범위의 시작 부분이 제거되었음에도 불구하고? 내 초기 기대는 BSD sed와 일치하는 "아니요"였지만 GNU sed는 "예"라고 답했으며 사양 텍스트를 확인해도 문제가 완전히 해결되지 않았습니다.

(적어도) 내 기대를 충족시키는 것은 macOS와 Solaris sed및 BSD 입니다 sed. GNU와 Busybox(적어도) sed그리고 여기의 많은 사람들은 동의하지 않습니다. 처음 두 개는 SUS 인증을 받았지만 다른 것들은 더 광범위할 수 있습니다.어떤 행동이 옳은가요?


이것규범적인 텍스트두 개의 주소 범위에 대해 말해보세요.

이것sed그러면 유틸리티는 명령이 다음 주기를 시작하거나 종료할 때까지 주소가 해당 패턴 공간을 순서대로 선택하는 모든 명령을 적용해야 합니다.

그리고

두 개의 주소가 있는 편집 명령은 첫 번째 주소와 일치하는 첫 번째 패턴 공간부터 두 번째 주소와 일치하는 다음 패턴 공간까지 포함 범위를 선택해야 합니다. [...] 선택한 범위 다음의 첫 번째 줄부터 시작하여 sed는 첫 번째 주소를 다시 찾습니다. 그런 다음 이 과정을 반복해야 합니다.

2호선이라고 할 수 있죠 이내에시작점이 삭제되었는지 여부에 관계없이 "첫 번째 주소와 일치하는 첫 번째 패턴 공간부터 두 번째 주소와 일치하는 다음 패턴 공간까지의 포함 범위"입니다. 반면에 첫 번째 사이클은 d범위에 시작할 기회를 주지 않고 다음 사이클로 들어갈 것으로 예상됩니다. UNIX™ 인증 구현은 내 기대를 충족하지만 사양 요구 사항을 충족하지 못할 수도 있습니다.

다음은 몇 가지 예시적인 실험이지만 핵심 질문은 다음과 같습니다.무엇~해야 한다 sed삭제된 행부터 범위가 시작되면 어떻게 해야 하나요?


실험 및 예시

문제에 대한 단순화된 데모는 다음과 같습니다. 이는 행을 삭제하는 대신 추가 복사본을 인쇄합니다.

printf 'a\nb\n' | sed -e '1d;1,2p'

이는 sed두 줄의 입력을 a제공 합니다 b. 이 프로그램은 두 가지 작업을 수행합니다.

  1. 첫 번째 줄을 삭제합니다 1d. d명령~ 할 것이다

    패턴 공간을 삭제하고 다음 루프를 시작합니다. 그리고

  2. 각 줄에 수신된 내용을 자동으로 인쇄하는 것 외에도 1~2줄의 범위를 선택하여 명시적으로 인쇄하는 것이 가능합니다. 따라서 이 범위 내에 포함된 행은 두 번 나타나야 합니다.

내 기대는 이것이 인쇄되어야한다는 것입니다

b

1,2단, 행 1에서는 범위에 도달하지 않았기 때문에(이미 다음 기간/행으로 점프했기 때문에) 범위가 적용되지 않으므로 삭제된 d동안 범위 포함이 시작되지 않습니다 . 일반적으로 aSolaris 및 BSD의 sed비 POSIX와 마찬가지로 macOS 및 Solaris 10에서 Unix를 준수하면 이 출력이 생성됩니다.sedsed

반면에 GNU sed는 인쇄합니다.

b
b

보여가지다범위가 설명되었습니다. 이는 POSIX 모드와 비 POSIX 모드 모두에서 발생합니다. Busybox의 sed도 동일한 동작을 합니다(그러나 동작이 항상 동일한 것은 아니므로 공유 코드의 결과는 아닌 것 같습니다).

추가 실험

printf 'a\nb\nc\nd\ne\n' | sed -e '2d;2,/c/p'
printf 'a\nb\nc\nd\ne\n' | sed -e '2d;2,/d/p'

삭제된 행부터 시작하는 범위를 다음과 같이 처리하는 것으로 나타났습니다.다음과 같은철사. 이는 /c/끝 범위와 불일치가 있기 때문에 표시됩니다 . /b/실제로 범위를 시작하는 데 사용아니요동작은 와 동일합니다 2.


내가 사용한 초기 작업 예제는 다음과 같습니다.

printf '%s\n' a b c d e | sed -e '1{/a/d;};1,//d'

첫 번째 줄에 있더라도 첫 번째 일치 /a/전에 모든 줄을 삭제하는 방법 입니다(GNU sed가 수행하는 작업 0,/a/d- 이는 POSIX 호환 변환을 시도한 것입니다).

이 항목은 최대한 제거해야 한다고 제안되었습니다.두번째첫 번째 줄이 일치하면 (또는 두 번째 줄이 일치하지 않으면 전체 파일) /a/이는 타당해 보이지만 다시 GNU sed만이 이를 수행합니다. macOS sed와 Solaris sed 모두 생성됩니다.

b
c
d
e

이것은 예상한 대로 작동합니다(GNU sed는 종료되지 않은 범위를 제거하여 빈 출력을 생성합니다. Busybox sed는 dsum 만 인쇄합니다 e. 이는 어쨌든 분명히 잘못된 것입니다). 일반적으로 말해서, 나는 그들이 인증 적합성 테스트를 통과했다는 사실이 그들이 올바르게 행동한다는 것을 의미한다고 가정합니다. 그러나 많은 사람들이 내가 확신하지 못한다고 제안했고 사양 텍스트는 완전히 설득력이 없으며 테스트 스위트도 그렇지 않습니다. 매우 포괄적입니다.

분명히 오늘 이 코드를 작성하는 것은 불일치로 인해 실제로 이식 가능하지는 않지만이론적으로그것은 어디에서나 이런저런 의미를 가져야 합니다. 나는 이것이 버그라고 생각하지만 어떤 구현에 대해 보고해야 할지 모르겠습니다. 현재 나의 견해는 GNU와 Busybox sed가 사양과 일관되지 않게 동작한다는 것입니다. 그러나 제가 착각할 수도 있습니다.

POSIX에는 무엇이 필요합니까?

답변1

이 질문은 2012년 3월 오스틴 그룹 메일링 리스트에 제기되었습니다. 이 문제에 대한 마지막 말은 다음과 같습니다(이 문제를 처음 제기한 Austin 그룹(POSIX를 유지 관리하는 조직)의 Geoff Clare가 제기함). 다음은 gmane NNTP 인터페이스에서 복사되었습니다.

Date: Fri, 16 Mar 2012 17:09:42 +0000
From: Geoff Clare <gwc-7882/[email protected]>
To: austin-group-l-7882/[email protected]
Newsgroups: gmane.comp.standards.posix.austin.general
Subject: Re: Strange addressing issue in sed

Stephane Chazelas <[email protected]> wrote, on 16 Mar 2012:
>
> 2012-03-16 15:44:35 +0000, Geoff Clare:
> > I've been alerted to an odd behaviour of sed on certified UNIX
> > systems that doesn't seem to match the requirements of the
> > standard.  It concerns an interaction between the 'n' command
> > and address matching.
> > 
> > According to the standard, this command:
> > 
> > printf 'A\nB\nC\nD\n' | sed '1,3s/A/B/;1,3n;1,3s/B/C/'
> > 
> > should produce the output:
> > 
> > B
> > C
> > C
> > D
> > 
> > GNU sed does produce this, but certified UNIX systems produce this:
> > 
> > B
> > B
> > C
> > D
> > 
> > However, if I change the 1,3s/B/C/ to 2,3s/B/C/ then they produce
> > the expected output (tested on Solaris and HP-UX).
> > 
> > Is this just an obscure bug from common ancestor code, or is there
> > some legitimate reason why this address change alters the behaviour?
> [...]
> 
> I suppose the idea is that for the second 1,3cmd, line "1" has
> not been seen, so the 1,3 range is not entered.

Ah yes, now it makes sense, and it looks like the standard does
require this slightly strange behaviour, given how the processing
of the "two addresses" case is specified:

    An editing command with two addresses shall select the inclusive
    range from the first pattern space that matches the first address
    through the next pattern space that matches the second.  (If the
    second address is a number less than or equal to the line number
    first selected, only one line shall be selected.) Starting at the
    first line following the selected range, sed shall look again for
    the first address. Thereafter, the process shall be repeated.

It's specified this way because the addresses can be BREs, but if
the same matching process is applied to the line numbers (even though
they can only match at most once), then the 1,3 range on that last
command is never entered.

-- 
Geoff Clare <g.clare-7882/[email protected]>
The Open Group, Apex Plaza, Forbury Road, Reading, RG1 1AX, England

Jeff가 (나에게서) 인용한 메시지의 나머지 부분 중 관련 부분은 다음과 같습니다.

I suppose the idea is that for the second 1,3cmd, line "1" has
not been seen, so the 1,3 range is not entered.

Same idea as in

printf '%s\n' A B C | sed -n '1d;1,2p'

whose behavior differ in traditional (heirloom toolchest at
least) and GNU.

It's unclear to me whether POSIX wants one behavior or the
other.

따라서 (Geoff에 따르면) POSIX는분명한GNU는 불법적으로 행동합니다.

실제로 , 일관성이 덜합니다 seq 10 | sed -n '1d;1,2p'(seq 10 | sed -n '1d;/^1$/,2p'"이상한").

누구도 이것을 GNU 사람들에게 버그로 보고하고 싶어하지 않습니다. 이것을 버그라고 생각해야 할지 모르겠습니다. 아마도 가장 좋은 선택은 두 가지 동작을 모두 허용하도록 POSIX 사양을 업데이트하여 어느 쪽에도 의존할 수 없다는 점을 분명히 하는 것일 것입니다.

편집하다. 1970년대 후반 Unix V7의 원래 구현을 살펴보니 sed숫자 주소의 동작이 의도되지 않았거나 적어도 완전히 고려되지 않은 것 같습니다.

대신, Geoff가 사양을 읽은 후(그리고 그 일이 발생한 이유에 대한 원래 설명) 다음 위치에 있습니다.

seq 5 | sed -n '3d;1,3p'

라인 1, 2, 4, 5는 이번에는 1,3pranged 명령이 한 번도 만난 적이 없는 끝 주소이기 때문에 출력되어야 합니다.seq 5 | sed -n '3d;/1/,/3/p'

그러나 이것은 원래 구현에서는 발생하지 않으며 내가 시도한 다른 구현에서도 발생하지 않습니다(busybox는 sed버그처럼 보이는 행 1, 2 및 4를 반환합니다).

당신이 보면UNIX v7 코드, 현재 줄 번호가 다음인지 확인합니다.더 큰(번호) 끝 주소보다 범위가 벗어났습니다. 사실은시작 주소에 대해서는 이 작업을 수행하지 않습니다.의도한 디자인이라기 보다는 실수로 보입니다.

이는 현재 구현이 실제로 이 측면에 대한 POSIX 사양의 해석을 따르지 않는다는 것을 의미합니다.

GNU 구현의 또 다른 혼란스러운 동작은 다음과 같습니다.

$ seq 5 | sed -n '2d;2,/3/p'
3
4
5

2번째 줄은 건너뛰었기 때문에 2,/3/3번째 줄에 입력하세요(숫자가 2보다 큰 첫 번째 줄). 하지만 우리를 만드는 것은 바로 이 선입니다.입력하다범위, 확인되지 않음주소. 상황이 더욱 악화됩니다 busybox sed.

$ seq 10 | busybox sed -n '2,7d; 2,3p'
8

2~7행이 삭제되었으므로 8행은 첫 번째 행 >= 2이므로 2,3 범위는 다음과 같습니다.입력하다그 다음에!

관련 정보