주소 범위가 이미 삭제 된 라인에서 시작하는`1d; 1,2d`에 POSIX sed에는 무엇이 필요합니까?


11

이 질문에 대한 의견 에서 다양한 sed 구현이 상당히 간단한 프로그램에 동의하지 않은 경우가 생겼으며 우리 (또는 적어도 I)는 사양이 실제로 필요한 것을 결정할 수 없었습니다.

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

1d;1,2d

해당 명령에 도달하기 전에 범위의 시작을 제거하더라도 2 행을 삭제해야합니까 ? 나의 초기 기대는 BSD sed와 "no"였고, GNU sed는 "yes"라고 말하고 사양 텍스트를 검사해도 문제가 완전히 해결되지는 않습니다.

내 기대와 일치하는 것은 (적어도) macOS와 Solaris sed및 BSD sed입니다. 의견이 맞지 않다는 것은 GNU와 Busybox (최소한)이며 sed여기에 많은 사람들이 있습니다. 처음 두 개는 SUS 인증을 받았으며 다른 두 개는 더 널리 퍼져있을 것입니다. 어떤 행동이 올바른가요?


두 주소 범위 의 사양 텍스트 는 다음과 같습니다.

나오지 명령이 다음주기 또는 종료 될 시작할 때까지 유틸리티는 다음 순서 누구의 주소가 패턴 공간을 선택 모든 명령에 적용된다.

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

2 행 시작점이 삭제되었는지 여부에 관계없이 "첫 번째 주소와 일치하는 첫 번째 패턴 공간에서 두 번째와 일치하는 다음 패턴 공간을 포함하는 범위" 내에 있습니다. 반면에, 나는 첫 번째 d사이클이 다음 사이클로 넘어갈 것으로 예상 하고 범위를 시작할 기회를주지 않았습니다. UNIX ™ 인증 구현은 예상 한대로 수행하지만 사양에서 요구하는 것은 아닙니다.

몇 가지 예시적인 실험이 뒤 따르지만 핵심 질문은 삭제 된 라인에서 범위가 시작될 때 어떻게 해야 sed 합니까?


실험 및 예

이 문제에 대한 간단한 데모는 다음과 같이 행을 삭제하지 않고 추가 사본을 인쇄합니다.

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

이것은 제공 sed입력의 두 라인, ab. 이 프로그램은 다음 두 가지를 수행합니다.

  1. 로 첫 번째 줄을 삭제합니다 1d. d명령

    패턴 공간을 삭제하고 다음 사이클을 시작하십시오. 과

  2. 모든 라인이 수신하는 자동 인쇄 외에도 1에서 2까지의 라인 범위를 선택하고 명시 적으로 인쇄합니다. 따라서 범위에 포함 된 선이 두 번 나타납니다.

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

b

1,2라인 1 동안 도달하지 않았기 때문에 범위가 적용되지 않는 경우에만 ( d이미 다음 사이클 / 라인으로 이동 했기 때문에 ) 범위 포함이 시작되지 않고 a삭제 된 동안에는 범위 포함이 시작되지 않습니다 . sedmacOS 및 Solaris 10 의 호환되는 Unix sed는 Solaris 및 BSD 의 비 POSIX와 마찬가지로이 출력을 생성합니다 sed.

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

b
b

범위 해석 했음을 나타냅니다 . 이것은 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는 dand 만 인쇄합니다 e. 일반적으로 인증 적합성 테스트를 통과했다는 것은 자신의 행동이 정확하지만 많은 사람들이 확실하지 않다고 제안했지만 사양 텍스트가 완전히 설득력이 없으며 테스트 스위트를 신뢰할 수 없다고 가정합니다. 완벽하게 포괄적입니다.

오늘날 불일치로 인해 해당 코드를 작성하는 것은 실제로 휴대하기 쉽지 않지만 이론적 으로는 어느 의미 또는 다른 의미로 모든 곳에서 동일해야합니다. 나는 이것이 버그라고 생각하지만 어떤 구현에 대해보고 해야할지 모르겠습니다. 내 견해로는 현재 GNU와 Busybox sed의 동작이 사양과 일치하지 않지만 잘못 생각할 수 있습니다.

POSIX에 필요한 것은 무엇입니까?


임시 해결 방법으로 임시 파일에 쓰고 POSIX로 처리하지 ed않고 sed완전히 무시 합니까?
D. 벤 크 노블

답변:


9

이것은 2012 년 3 월 Austin 그룹 메일 링리스트에서 제기되었습니다. 여기에 대한 최종 메시지가 있습니다 (오스틴 그룹의 Geoff Clare (POSIX를 유지하는 기관), 처음에 문제를 제기 한 사람). gmane NNTP 인터페이스에서 복사했습니다.

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

Stephane Chazelas <stephane_chazelas-Qt13gs6zZMY@public.gmane.org> 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/jkIBncuagvECLh61g@public.gmane.org>
The Open Group, Apex Plaza, Forbury Road, Reading, RG1 1AX, England

그리고 Geoff가 인용 한 나머지 메시지의 관련 부분은 다음과 같습니다.

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 사양을 업데이트하여 두 가지 동작 중 하나에 의존 할 수 없도록하기위한 것입니다.

편집 . 나는 sed70 년대 후반부터 Unix V7 의 원래 구현을 살펴 보았으며 숫자 주소의 동작이 의도되지 않았거나 적어도 완전히 생각하지 않은 것처럼 보입니다.

반대로 Geoff가 스펙을 읽고 (그리고 왜 그런지에 대한 나의 원래 해석), 반대로,

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

1 번, 2 번, 4 번 및 5 번 줄이 출력되어야합니다 1,3p.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 범위가 입력됩니다 !


1
따라서 문제가 여전히 해결되지 않은 것처럼 들립니다. 문제가 발생한 이유에 대한 귀하의 추론에 동의하지만, 그것이 원하는지 확실하지 않습니다. 또한 Geoff가 인용 된 텍스트에 의해 UNIX ™ 구현이 가능하다는 것을 확신하는 것처럼 들립니다. 정확했다. 그것도 당신의 독서입니까?
Michael Homer

1
@MichaelHomer, 아이디어는 그 POSIX가 (제프에 따라)이다 명확한 는 GNU 동작은 비 호환입니다. 그리고 사람들에게 놀라 울 정도로 범위가 어떻게 처리되는지 알지 못하더라도 일관성이 떨어집니다 ( seq 10 | sed -n '1d;1,2p'와 비교 seq 10 | sed -n '1d;/^1$/,2p'). 아무도 GNU 사람들에게 버그로보고하지 않았습니다. 나는 그것이 버그로 자격이 있는지 확신 할 수 없다. 아마도 가장 좋은 옵션은 POSIX 사양을 업데이트하여 두 가지 동작 중 하나에 의존 할 수 없도록 명확하게하는 것입니다.
Stéphane Chazelas

2
실제로 POSIX 정의는 주소 범위를 시작하거나 종료하기 위해 주소를 "보아야"한다는 진술을하지 않기 때문에 IMO의 GNU 구현은 POSIX 문구를보다 엄격하게 따릅니다 (GNU에 대해 놀랍습니다!). 이것은 내가 아는 대부분의 실제 사례에서도 바람직한 동작입니다. 그러나 지적했듯이 일관성이 있어야합니다. 그리고 이후에도 각 라인에 범위 패턴이 있는지 확인 d하는 것은 성능 문제 일뿐만 아니라, 범위에 필요한 "보이지 않는"패턴이 더 이상 빈 패턴에 영향을 줄 수 없기 때문에 추가 구현 문제가 발생합니다.
Philippos

@Philippos, 해당 1d;1,2p스크립트에서 1,2p명령은 첫 번째 행에서 실행되지 않으므로 첫 번째 주소패턴 공간 과 일치하지 않으므로 텍스트를 해석하는 한 가지 방법입니다. 어쨌든, 주소 평가는 명령이 실행될 때 이루어져야합니다. 처럼sed 's/./x/g; /xxx/,/xxx/d'
Stéphane Chazelas

2
@Isaac, 이것이 문제의 핵심입니다. POSIX의 언어에서 1/1/모두 주소입니다, 1행 번호가 1 인 경우 주소는입니다 /1/패턴 영역이 포함되어있는 경우 주소입니다 1"문제는 주소의 두 가지 유형이 동일하게 취급해야한다, 또는 행 번호 범위를 고려하는 경우는 여부, 일치 여부에 관계없이 절대적으로 " 역사적 배경에 대한 최신 편집을 참조하십시오.
Stéphane Chazelas
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.