stdin이 닫힐 때까지 반복되는 sh 스크립트 - 이것을 어떻게 테스트합니까?

stdin이 닫힐 때까지 반복되는 sh 스크립트 - 이것을 어떻게 테스트합니까?

입력 스트림을 파이프하려고 하는데 다운스트림 파이프라인 프로그램이 실패할 수 있는 상황을 포착하고 싶습니다. 이 경우 다시 시작해야 합니다. 그래서 나는 그것을 루프에 넣었습니다.

step1 |while true ; do step2 ; done

그러나 업스트림 파이프가 닫히면 루프가 종료되기를 원합니다. 2단계의 종료 상태에서는 이를 알 수 없습니다. 그렇지 않으면 다음과 같이 말했을 수도 있습니다.

step1 |until [ $? -ne 0 ] ; do step2 ; done

stdin이 닫혀 있는지 확인하지만 실제로 stdin의 문자를 사용하지 않는 테스트가 필요합니다.

C에서는 어떻게 하는지 궁금합니다. 버퍼가 0인 read(2)를 사용하여 이것을 테스트할 수 있습니까? 나는 그렇게 생각하지 않습니다. 옵션 (2)는 어떻습니까? 아니요. 아니면 그럴까요? fcntl(2)은 어떻습니까? 아무것도 찾을 수 없습니다.

바이트를 소비하고 어떻게든 다시 출력하는 것 외에는 정말 다른 방법이 없나요? 파일 설명자를 닫지 않고 테스트하시겠습니까?

답변1

적어도 Linux에서는 poll()이벤트 마스크에서 with를 사용하여 파이프의 다른 쪽 끝이 닫혔는지 알 수 있습니다.POLLHUP

그러나 이 시점에서 읽을 데이터가 파이프에 아직 남아 있을 수 있으므로 해당 데이터도 확인하는 것이 좋습니다. Linux에서는 ioctl을 통해 이 작업을 수행할 수 있습니다 FIONREAD.

따라서 다음 중 하나를 정의할 수 있습니다.

stdin_alive() {
  perl -MIO::Poll -e '
    require "sys/ioctl.ph";
    -p STDIN or die "stdin is not a pipe\n";
    $p = IO::Poll->new;
    $p->mask(STDIN, POLLHUP);
    if ($p->poll(0)) {
      ioctl(STDIN, &FIONREAD, $n) or die "FIONREAD: $!\n";
      $n = unpack "L", $n;
      exit 1 unless $n;
    }'
}

다음과 같이 사용하십시오.

step1 | while stdin_alive; do step2; done

ifne또 다른 방법은 다음 명령을 사용하는 것입니다 moreutils.

step1 |
  while
    ifne sh -c 'step2 && exit 42'
    [ "$?" -eq 42 ]
  do
    continue
  done

ifne표준 입력을 읽어보십시오. 적어도 1바이트를 읽으면 ifne명령이 시작되고 해당 표준 입력이 새 파이프에 연결되며, 해당 새 파이프를 통해 표준 입력에서 읽은 내용이 명령에 삽입되므로 추가 삽질이 발생하므로 효율성이 떨어집니다. 전송을 위한 추가 파이프가 있지만 이는 입력 유형(파이프뿐만 아니라)에 관계없이 작동한다는 의미입니다.

이전 솔루션과의 또 다른 차이점은 ifne시작하기 전에 stdin에 대한 입력을 기다리는 step2반면, poll()+ FIONREAD메소드는 파이프가 활성 상태인지, 검사 시점의 정확한 시점에 데이터가 있는지만 확인한다는 것입니다. 그러나 POLLIN이는 폴링되는 이벤트 목록에 추가하여 변경할 수 있습니다.

관련 정보