프로세스 무한 루프 입력 리디렉션 종료

프로세스 무한 루프 입력 리디렉션 종료

편집: 내가 실행하려고 했던 프로그램에 모든 입력을 스캔한 후 무한 루프가 있다는 것을 깨달았습니다. 그런 다음 무한히 인쇄하면 EOF를 읽지 않습니다. 마지막 입력을 읽은 다음 무한 루프에 들어갑니다.

예를 들어 이런 프로그램이 있다고 해보자.

printf("%c\n", getch());
while(1)
{
   printf("%c\n", getch());
}

입력 내용을 모두 읽은 후 프로그램을 종료할 수 있는 방법이 있습니까? 입력 파일 리디렉션이 완료되면 프로그램을 종료할 수 있기를 원합니다. (프로그램이 입력 파일에서 마지막 문자를 가져올 때) 참고: 실행 중인 프로그램을 수정할 수는 없지만 이 프로그램을 실행하는 스크립트는 수정할 수 있습니다.

지금은 프로그램을 실행하기 위한 스크립트가 있습니다. 기본적으로 이는 입력 + 출력을 결합/병합하는 데 도움이 됩니다.

편집: 누군가가 내 이전 문제를 해결하는 데 도움을 주었습니다. || 추가하려고 했는데 || 이 추적을 중단했지만 상단의 편집 내용에 새로운 문제가 있습니다.

mkfifo strace.fifo
{
  while read -d, trace; do
    if [[ $trace = *"read(0" ]]; then
       IFS= read -rn1 answer <&3 || break
       echo "$answer" >> in
       answer=${answer:-$'\n'}
       printf %s "$answer" >&2
       printf %s "$answer"
    fi
  done < strace.fifo 3< input | strace -o strace.fifo -e read stdbuf -o0 ./a.out &
} >> $fname.out 2>&1

그래서 지금 저는 절전 모드를 사용하고 프로그램을 종료하여 프로그램을 종료하려고 시도하는 매우 해킹적인 방법을 가지고 있습니다. 또한 지금까지 사용한 입력을 확인하고 입력 파일과 비교하고 있습니다. 이것은 현재 스크립트에 타이머가 여러 개 있고 비교가 아래 코드와 비슷한 경우에 대한 작은 예일 뿐입니다. 그러나 이 방법은 좋은 방법이 아닙니다. 왜냐하면 프로그램이 입력 파일 읽기를 완료하지 않으면 프로그램이 종료되지 않기 때문입니다. 내 실제 스크립트에서는 이러한 if 문을 여러 개 사용했으며 시간의 80% 정도 작동하지만 때때로 타이머와 프로그램 실행 방식의 변동으로 인해 올바른 작업을 수행하지 못할 수도 있습니다.

sleep .05
awk 'BEGIN{ORS="";} NR==1{print; next;} /^[^ ]/ { print; next; } {print "\n";}' in > temp
diff -w -B temp input > /dev/null
# Check if input done yet
if [ $? -eq 0 ] ; then
   # Check if program still running and input done
   if [ "$(pidof a.out)" ] ; then
      killall -15 a.out > /dev/null 2>&1
   fi
fi

그렇다면 입력이 완료된 후 kill처리하는 방법이 있는지 궁금합니다 . strace또한 입력과 출력을 함께 병합할 수 있기를 원합니다.

답변1

훨씬 더 쉬운 솔루션이 있다고 생각하지만 그것이 얼마나 이식성이 있는지 잘 모르겠습니다. 고려하다:

$ cat trunc.c
#include <stdio.h>

int main() {
    int c;
    while(((c = getchar()) != EOF) && ((c & 0xff) != 0xff))
        putchar(c);
    return 0; 
}

이는 2의 보수 시스템에서 (-1 & 0xff) == 0xff. 이것은 EOF를 문자로 인쇄하는 프로그램을 포착합니다. 나는 그것을 테스트했다:

your_buggy_source_gen < any_ascii_file | trunc

cat any_ascii_file이는 값이 0xff인 옥텟이 없는 경우 와 동일합니다 .

답변2

"이제 모든 입력을 읽기 전에 프로그램이 무한 루프에 빠지는지 확인하는 방법이 있는지 궁금합니다. 예를 들어 프로그램이 무한 루프에 빠지면 프로그램을 중지하는 유일한 방법입니다."

우리는 다음에 대한 답을 알고 있습니다.그 질문은 거의 80년 동안. 대답은 '아니오'입니다. 방법이 없습니다.

실제 질문에 가깝지도 않은 질문을 해주셔서 감사합니다.

"학생의 결과물을 평가하려고 합니다. 나중에 사용할 수 있도록 스크립트를 만들고 싶습니다. 지금은 수면 타이머를 사용하여 꽤 잘 작동하고 있지만 타이머 없이 스크립트를 더욱 강력하게 만들고 싶습니다."

간단한 솔루션:

# how many seconds of CPU (not wall clock)
# should the student's program get?
# 10 seconds is generous for an intro class
# 60 seconds of CPU would be obscene
$ ulimit -t 10
$ run_student_program

# but since I don't have a student program

$ time dd if=/dev/zero of=/dev/null
Killed

real    0m9.998s
user    0m3.080s
sys     0m6.912s

답변3

정확히 쉘 프로그래밍 팁은 아니지만 현실은 소스 코드를 수정할 수 없더라도 손상된 프로그램의 동작을 수정해야 한다는 것입니다.

이를 수행하는 한 가지 방법은 실제 "read()" 시스템 호출을 호출한 다음 파일 끝 조건을 만나면 종료되는 방식으로 "read()" 시스템 호출을 가로채는 LD_PRELOAD 모듈입니다. (이상적으로는 "getchar()"를 가로채지만 이는 일반적으로 함수 호출이 아닌 매크로이므로 가로챌 수 없습니다.)

또 다른 방법은 디버거에서 코드를 실행하고 코드가 무한 루프에 들어가는 위치를 찾은 다음 실행 파일을 수정하거나 잘못된 기능을 대체하는 LD_PRELOAD 모듈을 다시 적용하여 바이너리를 패치하는 것입니다.

또는 이전 답변에서 제안한 대로 수행하고 잘못된 프로그램이 입력 끝에 도달했음을 나타내는 내용을 출력할 때 입력을 닫는 항목으로 출력을 파이프할 수 있습니다. (이것은 그것에 의존한다는 점에 유의하십시오.~ 아니다이 경우에는 공정한 가정인 SIGPIPE를 트래핑합니다.)

보다 정교한 버전은 입력 파일 설명자를 읽지 않고 끝에 도달했는지 모니터링하는 다른 프로그램과 공유하는 것입니다. 그러나 이는 특히 까다로운 작업이며, 특히 파이프나 소켓 또는 장치를 다루는 경우 더욱 그렇습니다.

잘못된 프로그램이 stdin에서 읽는다고 가정하고 다음과 같이 래핑하세요.

  #!/bin/sh
  나쁜 프로그램 실행 "$@" &
  pid=$!
  펄 -MFcntl=:모드 -e '
    @S = stat STDIN 또는 die "잘못된 입력; $!\n";
    S_IFREG($S[2]) 또는 die "입력이 일반 파일이 아닙니다\n";
    while (sysseek(STDIN,0,1) != $S[7]) { 수면 1 }
  '
  $pid를 죽여라
  기다리다

답변4

실제로 손상된 프로그램을 수정해야 하지만 그렇게 할 수 없는 경우 쉘에서 파일을 cat하여 프로그램에 파이프한 다음 종료하기 전에 1~2초 동안 휴면하여 파이프를 닫고 종료함으로써 문제를 해결할 수 있습니다. SIGPIPE를 이용한 프로그램.

(cat file ; sleep 2) | stupid_program

관련 정보