2010-04-22 2 views
2

유닉스에서 실행되는 프로그램이 있는데, 완료되면 '완료되었습니다'라는 메시지가 인쇄되지만 종료되지는 않습니다. 프로세스가 종료되면 (명령의 출력을 검사하여) 자동으로 감지하여 프로세스를 종료하고 다른 작업을 계속할 수 있도록합니다. 이 스크립트를 여러 번 동시에 실행할 수 있기를 원하기 때문에 복잡합니다. (내가해야 할 일은 스크립트가 다양한 입력으로 호출되도록 요구하지만, 스크립트가 실행될 때마다 반환하는 데 시간이 걸리므로 병렬로 처리하기를 원합니다.)프로세스가 끝났을 때 감지 (그러나 종료하지 않음)

누구나 비슷한 작업을 했습니까? 이? 명령의 stderr 및 stdout 출력을 임의의 파일 이름을 가진 임시 파일로 리디렉션 한 다음 파일 및 파이프를 끝 조건 (즉, 특정 로그 행)에 대해 grep로 끝낼 수 있습니다. 문제는 확실히 tail -f가 계속 실행되어 결국 빠져 나올 수 없다는 것입니다. 설문 조사를해야합니까? 그렇다면 최상의 접근 방식은 무엇입니까?

+0

불행히도 저는 오래된 Solaris mac bash 2.x가있는 hine; 기대하지 마라. 그리고 grep이없는 것처럼 보입니다. --max-count = 1 – Egwor

답변

2

# 기대

스폰/home/foo/myjob
"Completed successfully"

+0

이것이 실제로 프로세스를 종료시키지 않는다고 생각합니다. 스폰 된 모든 프로세스가 SIGHUP을 보낸 후 완료 될 때까지 기다릴 것으로 예상합니다. 질문 나는 이것이 오작동하는 프로그램이라는 것을 모았습니다. 그래서 SIGHUP은 아마도 많은 일을하지 않을 것입니다 ... 당연히 스폰가 리턴하는 PID를 잡아서 기대 한 후에 exec kill을 실행할 수 있습니다. – wich

+0

@wich 사실이라 할지라도, 그 과정은 어쩔 수없이 처리되어야 할 것입니다. 그러나 확실하게 원하는 신호를 명시 적으로 보낼 수 있습니다. 나는 단지 내가 생각할 수있는 모든 접근 방식만큼 우아하게 "Completed successfully"를 기다리는 것을 기대가 처리한다고 생각합니다. – frankc

2

폴링 할 필요가 없습니다. inotifywait과 같은 inotify 도구를 사용하여 출력 파일이 변경된시기를 감지 한 다음이를 grep하고 필요한 경우 프로세스를 종료 할 수 있습니다. 즐거운 사냥!

+0

매우 재미 있습니다. 불행히도 저는 오래된 솔라리스 머신에서 실행하고 있습니다 : ( – Egwor

0

이것은 bash의 과잉 공격 일 수 있습니다. 어쩌면? 파이썬을 사용한다면, subprocess 모듈을 사용하여 자신의 프로그램과 하위 스크립트 사이에 통신 채널을 열어 둘 수 있습니다. threading 모듈을 사용하면 여러 개의 하위 스크립트 실행을 동시에 시작할 수 있습니다.

"성공적으로 완료"를 출력 한 후 스크립트가 아무 것도 출력하지 않습니까? 그렇지 않다면 출력 된 마지막 x 문자 (제안한 임의의 파일로 마지막 행을 얻기 위해 tail -n 1을 사용하여)를 폴링하고 '성공적으로 완료'했는지 확인하십시오. 그러나 스크립트가 나중에 인쇄물을 계속 남기면 선을 놓칠 수 있습니다.

또는 grep을 "completed successfully"로 출력 할 수 있습니다.

0

몇 가지 임의의 아이디어. (1) 그것이 프로그램이라면, 그것을 더 유용하게 나타 내기 위해 그것을 수정할 수 있습니다. (2) 프로세스 목록 (ps ax)을 보면 "Completed"메시지를 출력하려고 할 때 I/O 대기 상태가되는 것을 볼 수 있어야합니다. (3) 나는이 목적을 위해 pseudo tty가 존재한다고 믿습니다. 임시 파일을 사용하지 않고도 stdout을 직접 볼 수 있습니다.

0

1 가능한 솔루션 : tempfile1 "성공적으로 완료"
your_program> tempfile1
그렙 -i; if [$? -eq 0]; then i =`pidof your_program`; $ i를 죽인다. fi

첫 번째는 리디렉션입니다. grep의 종료 상태에 대한 두 번째 점검. 0 (성공)이면 프로그램의 PID를 가져 와서 종료합니다.
이것은 "생각 빨리"하는 운동이었습니다. 그것은 작동해야합니다. 단점은 한 번에 하나의 프로그램 인스턴스 만 실행할 수 있지만 적응은 가능하며 병렬로 실행할 수 있다는 것입니다.

편집 - 27.05.2010 :
2 해결 방안 :
꼬리 --pid =`이것들을 pidof your_program` -f -n0 tempfile1 | AWK '/ 완료/{($ (1) == "완료") {시스템의 경우;} ("내가 =`your_program` 이것들을 pidof 나는 $ 죽이기")}'이 긴 줄을, &

그럼 당신이하지 더 이상 루프/crontab이 필요합니다.설명 :
--pid =`pidof your_program`은 지정된 PID가 끝난 후 꼬리표를 만듭니다. 이렇게하면 프로그램이 죽을 때 꼬리가 함께 죽습니다.
-n0은 tempfile1의 다른 "완료"문을 무시합니다 (따라서 항상 tempfile1을 먼저 자르므로 걱정할 필요가 없습니다).
awk는 프로그램에서 throw 된 "Completed"문을 검색하고 {system} 부분은 프로그램에서 kill을 실행합니다.
&도 잊지 말고 전체 배경으로 사용하십시오.
재미있게 보내십시오.

+0

4 개의 공백으로 코드를 들여 쓰기하면 들여 쓰기와 줄 바꿈을 유지하는 코드 블록으로 포맷됩니다 – wich

+0

그래도 루프를 수행해야합니다. 그런 다음 'Completed successfully'가 몇 분 동안 도착하지 않으면 grep이 실패합니다. 내가 사용할 수있는 프로세스가 상당히 제한적인 것 같아서 개념이 마음에 들지만. – Egwor

+0

예, 루프 또는 또 다른 솔루션을 생각해 냈습니다. (코멘트에서 코드의 형식을 지정할 수 없기 때문에 기본 게시물을 편집했습니다.) – w00t

1

여기에 내 찌르다, 꽤 잘 작동하지만, 매번 kill을 호출하면 전체 서브 쉘 스크립트가 콘솔에 출력되고 나는 그것을 억누를 수없는듯한 살해 메시지라고하기 때문에 오히려 스팸 메일입니다. (stdout과 stderr를/dev/null로 리디렉션해도 도움이되지 않습니다.)

참고 : 실행하려면 bash4가 필요합니다. $BASHPID은 4 이상에서만 사용할 수 있으며 $$은 하위 쉘이 아닌 상위 쉘의 PID를 제공하기 때문에 대안이 아닙니다.

!/bin/bash 

for i in {1..8}; do 
    (
    mypid=$BASHPID 
    (
     #subshell to simulate started process 
     sleep 2 
     echo finished 
     while : ; do 
     : 
     done 
    ) | \ 
    { 
     while read line; do 
     if [[ $line == finished ]]; then 
      break; 
     fi 
     done 
     echo process done, killing $mypid... 
     kill -9 $mypid 
    } 
) & 
done 
wait 
1

다음 래퍼 스크립트는 FIFO에 쓸 것입니다 출력을 파이프, 실제 명령을 호출합니다. !

#!/bin/bash 

# cmd to run 
expected_output=$1 
shift 
cmd=("[email protected]") 
# where to read commands output 
mkfifo /tmp/killonoutput.$$ 
# start cmd async 
"${cmd[@]}"|tee /tmp/killonoutput.$$ 2>/dev/null & 

if grep -q --max-count=1 "$expected_output" /tmp/killonoutput.$$;then 
    kill %1 
    echo "Killed ${cmd[@]}" 
fi 
# grep returned so fifo was closed 
rm /tmp/killonoutput.$$ 

샘플 실행 : 래퍼 스크립트는 예상 문자열이 는 FIFO에서을 greped 때, 실제 명령을 죽일 /는/usr/빈

./killonoutput.sh "Finished" bash -c "echo sleeping;sleep 3;echo Finished; sleep 10000" 
sleeping 
Finished 
Killed bash -c echo sleeping;sleep 3;echo Finished; sleep 10000 
./killonoutput.sh: line 17: 19553 Terminated    "${cmd[@]}" 
    19554      | tee /tmp/killonoutput.$$ 2> /dev/null