GNU `sed`가 때때로 분기 명령 없이 루프를 생성하는 이유는 무엇입니까?

GNU `sed`가 때때로 분기 명령 없이 루프를 생성하는 이유는 무엇입니까?

다음과 같은 놀라운 실험 sed코드를 살펴보세요.

seq 3 | timeout 5s sed 'H;${g;D}'

... timeout 5s이것이 없으면 컴퓨터가 정지되지만(5초 후에 정지하지 않고) 먼저 다음과 같은 결과가 출력됩니다.

1
2

또는 p홀딩 버퍼를 끝없이 인쇄하려면 다음을 추가하세요.

seq 3 | timeout 5s sed 'H;${g;p;D}'

이상하게 D도 명령만 무한 루프를 일으키는 것 같습니다(dp, 또는 ) 로 바꾸려고 시도했지만 P잘 문서화되어 있지 않습니다. 이것암소 비슷한 일종의 영양 sed info문서에는 다음과 같이 나와 있습니다.

'D'
     If pattern space contains no newline, start a normal new cycle as
     if the 'd' command was issued.  Otherwise, delete text in the
     pattern space up to the first newline, and restart cycle with the
     resultant pattern space, without reading a new line of input.

그러나 이는 사용자에게 무한 루프 가능성을 경고하지 않습니다. 아마도 g;D내부 행 카운터가 재설정되어 sed바로 뒤로 점프할 것입니다 $.

분기 문이 없는 이런 종류의 루프가 어디에도 문서화되어 있습니까? 그렇지 않다면 누군가 그것이 어떻게 작동하는지 설명할 수 있습니까?

답변1

예, 이것은 이상한 문제이지만 분명히 예상된 문제입니다.

핵심 이유를 단계별로 살펴보겠습니다.

테스트에서는 seq 5 | sed 'H;${g;d}'한 줄에 하나씩 1부터 4까지 인쇄하지만 마지막 숫자는 인쇄하지 않습니다. 5왜 그렇습니까?

속도:

  • seq 5한 줄에 하나씩 1부터 5까지의 모든 숫자를 생성합니다.
  • sed첫 번째 줄이 수신 되면 1예약된 공간에 저장됩니다(기본적으로 개행 문자를 추가한 후 H).
  • 실행할 다른 항목이 없기 때문에(다음 명령은 마지막 줄에서만 실행됩니다 $) 해당 줄도 인쇄됩니다(홀딩 공간 제외).
  • 각 줄에 대해 추가된 개행 문자 뒤의 예약된 공간에 추가되어 인쇄됩니다.
  • 마지막 줄에서 명령이 g;d실행됩니다. 첫 번째는 이때 예약된 공간 전체를 호출해 \n1\n2\n3\n4\n5즉시 사용 하고 중지 d하는 방식이다 .

예약된 공간의 상태를 실제로 보려면 다음 sed 스크립트를 실행할 수 있습니다.

$ seq 5 | sed 'H;x;l;x;${g;d}'
\n1$
1
\n1\n2$
2
\n1\n2\n3$
3
\n1\n2\n3\n4$
4
\n1\n2\n3\n4\n5$

D동일하게 작동한다고 가정d거대한차이점:오직패턴 공간에 새로운 라인이 없을 때. ~에서info sed

'D'
패턴 공간에 줄 바꿈 문자가 포함된 경우 첫 번째 줄 바꿈 문자까지 패턴 공간의 텍스트를 삭제하고 새 입력 줄을 읽지 않고 결과 패턴 공간으로 루프를 다시 시작합니다.

패턴 공간에 개행 문자가 포함되어 있지 않으면 "d" 명령이 실행된 것처럼 일반적인 새 루프가 시작됩니다.

따라서 d다음으로 바꿀 때 D이 스크립트를 실행하십시오 .

seq 5 | sed 'H;x;l;x;${g;D}'

무제한 출력을 얻을 수 있습니다. 첫 번째 줄을 제거합니다 D: 숫자와 줄 바꿈, 그렇습니다. 하지만 처음으로 돌아가서(삭제되지 않음) 1\n2\n3\n4\n5패턴 공간의 예약된 공간에 추가됩니다. 첫 번째 루프에서는 a가 예약된 공간 1\n2\n3\n4\n5에 추가되어 두 배가 됩니다. 각 주기의 정확한 값은 중요하지 않습니다. 중요한 것은 각 주기마다 값이 커진다는 것입니다.\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5\n1\n2\n3\n4\n5

이제 이전 패턴 공간을 지우면 D작동할 수 있습니다.

$ seq 5 | sed 'H;x;l;x;${g;z;D}'
\n1$
1
\n1\n2$
2
\n1\n2\n3$
3
\n1\n2\n3\n4$
4
\n1\n2\n3\n4\n5$

물론.

놀라운 부작용을 제외하고는 평범하지 않고 모든 것이 예상대로 작동했습니다.

관련 정보