백그라운드에서 실행중인 쉘 스크립트 종료


12

inotifyt-tools의 inotifywait 유틸리티를 사용하여 디렉토리를 모니터하는 쉘 스크립트를 작성했습니다. 해당 스크립트가 백그라운드에서 계속 실행되기를 원하지만 원하는 경우 스크립트를 중지하고 싶습니다.

지속적으로 실행하려면 다음을 사용했습니다 while true. 이처럼 :

while true;
do #a set of commands that use the inotifywait utility
end

파일에 파일을 저장 /bin하고 실행 파일로 만들었습니다. 백그라운드에서 실행되도록 nohup <script-name> &터미널을 사용 하고 닫았습니다.

이 스크립트를 어떻게 중지해야하는지 모르겠습니다. 나는 답변 살펴 보았다 여기 와 매우 밀접하게 관련 질문이 여기에 .

업데이트 1 : 아래 @InfectedRoot의 답변을 바탕으로 다음 전략을 사용하여 문제를 해결할 수있었습니다. 처음 사용

ps -aux | grep script_name

sudo kill -9 <pid>프로세스를 종료 하는 데 사용 합니다. 그런 다음 반환 된 ID로 다시 pgrep inotifywait사용해야 sudo kill -9 <pid>했습니다.

이것은 작동하지만 이것이 지저분한 접근법이라고 생각합니다. 더 나은 대답을 찾고 있습니다.

업데이트 2 : 대답은 두 프로세스죽이는 것으로 구성 됩니다 . 이것은 명령 행에서 스크립트를 실행하면 2 개의 프로세스, 1은 스크립트 자체 , 2는 inotify 프로세스를 시작하기 때문에 중요 합니다 .



2
-9옵션을 제거 kill하고 사용 kill하면 엉망이됩니다.
Sree

1
브라보. 펑 현금 상자에 '$$'를 다시 넣으려면 -9옵션이 kill여기에 있음 을 강조하고 싶습니다 . : P
syntaxerror

완전성을 위해 한 번에 두 프로세스를 모두 종료하는 깔끔한 접근 방법이 있습니다. 프로세스를 개별적으로 종료하는 대신 스크립트의 프로세스 그룹을 종료하여 한 번에 종료 할 수 있습니다. pgid 인수는 셸 스크립트의 주요 프로세스의 PID와 같은과에 동일합니다 kill: 당신이 마이너스로 pgid를 앞에 그것을 kill -- -<pgid>, kill -9 -<pgid>
cg909

답변:


6

개선하려면을 사용 killall하고 다음 명령을 결합하십시오.

ps -aux | grep script_name
killall script_name inotifywait

또는 한 줄로 모든 것을 수행하십시오.

killall `ps -aux | grep script_name | grep -v grep | awk '{ print $1 }'` && killall inotifywait

위의 솔루션은 작동하지만 한 줄 명령은 작동하지 않습니다. 확인해주세요. 오류가 발생했습니다 : 처리 없음
light94

@ light94 Error: no process는 이미 당신이 그것을 죽였다는 것을 의미해야합니다. VLC & Geany 와 같은 두 개의 다른 프로그램을 열고 대신 사용해보십시오.
cremefraiche

earer가 귀하의 코드가 작동한다고 말했듯이 @cremefraiche ..하지만 대체 솔루션을 찾고 있으며 가장 일반적인 해결책은 kill <pid> 사용하는 것입니다. 내 스크립트가 그런 식으로 끝나지 않기 때문에 코드가 부적절하다면 조금 걱정이 되나요? 저를 안내해 주시겠습니까?
light94

당신은 절약 할 수 grep -v grep켜서 grep script_name으로 grep -e "[s]cript_name".
nmichaels

3

다음을 사용하여 백그라운드 작업 나열

# jobs

그런 다음 이전 작업 수를 선택하고 실행하십시오.

# fg 1 

여기에 이미지 설명을 입력하십시오

포 그라운드로 가져올 것입니다.

그런 다음 CTRL + C를 사용하여 죽이거나 더 쉬운 방법으로 스크립트의 PID를 찾으십시오.

ps -aux | grep script_name

여기에 이미지 설명을 입력하십시오

그런 다음 pid를 사용하여 죽이기

sudo kill -9 pid_number_here

2
첫 번째 옵션은 스크립트를 지정한 후 셸을 닫고 작업 명령이 동일한 셸에서만 작동한다고 생각하기 때문에 제 경우에는 유효하지 않습니다. 또한 두 번째 옵션을 시도했지만 프로세스가 종료되지만 pgrep inotifywait를 수행하면 프로세스로 볼 수 있습니다.
light94

작업은 쉘을 닫아도 작업 목록을 제공합니다. 여전히 프로세스는 완료됩니다.
Babin Lonston

2
나는 그것을 시도했지만 그것을하지 않았다.
light94

@ light94 당신이 맞아요. 여기서는 jobs명령이 실제로 쉘 있는 동안 실행중인 작업 만 표시하는 경우가 자주있었습니다 . 특정 터미널 창을 닫으면 액세스 할 수있는 유일한 방법은 해당 방법입니다 ps(위의 내용 참조). 그래서 당신이 이것을 만들지 않는 것이 확실합니다.
syntaxerror

2

당신은 사용할 수 있습니다 ps+ grep또는 pgrep프로세스 얻기 위해 이름 / PID ; 나중에 killall/ pkill를 사용 kill하여 프로세스 이름 을 죽이거나 pid를 죽일 때 사용하십시오 . 다음은 모두 작동해야합니다.

killall $(ps aux | grep script_name | grep -v grep | awk '{ print $1 }') && killall inotifywait
(ps -ef | grep script_name | grep -v grep | awk '{ print $1 }' | xargs killall) && killall inotifywait
(ps -ef | grep script_name | grep -v grep | awk '{ print $2 }' | xargs kill) && killall inotifywait
(pgrep -x script_name | xargs kill) && pkill -x inotifywait
pkill -x script_name && pkill -x inotifywait

가장 중요한 것은 당신이 죽이고 자 하는 정확한 프로세스 만 죽여야 한다는 것입니다.

pkill/ 는 정확한 이름이 아닌 패턴pgrep 과 일치 하므로 더 위험합니다. 여기 에 정확한 이름과 일치하도록 추가되었습니다.-x

또한 사용시 pgrep/ pkill필요할 수 있습니다

  • -f(같은 전체 명령 줄을 일치하도록 ps aux않습니다)
  • -a 프로세스 이름도 인쇄합니다.

위의 실행 후 각 사용 오류가 발생합니다. 복사하여 스크립트 이름을 바꾸고 있습니다. kill as output으로 출력을
얻었습니다

script_name이 실행 중입니까? 그것은 나를 위해 작동합니다 (debian jessie)
Hongxu Chen

예, 실행 중입니다. 귀하의 솔루션은 위의 @cremefraiche 솔루션과 거의 동일하므로 동일한 방식으로 작동 할 것으로 예상했습니다
./

예, 가능한 방법, 특히 pgrep/를 추가하여 요약했습니다 pkill. 그래도 문제가 해결 pgrep되지 않으면 -x없이 시도해보십시오 . 기본적으로 다른 프로세스가 일치하는지 확인하지 않고 한 줄 명령으로 프로세스를 종료하는 것이 좋지 않다고 생각합니다.
Hongxu Chen

1

당신은 아마 이것을 할 수있는 많은 방법이 있다고 말할 수 있습니다.

"업데이트 # 2"와 관련하여 일반적으로 부모-자식 계층에서 프로세스를 종료하면 일반적으로 모든 관련 프로세스가 종료됩니다. 그러나 이것에는 많은 예외가 있습니다. 프로세스 트리에서 최종 '자식'을 종료하는 것이 이상적입니다. 그런 다음이 자식의 부모는 실행할 다른 작업이없는 경우 종료해야합니다. 그러나 부모를 죽이면 부모가 죽을 때 신호가 아이들에게 전달되어야하고 아이들도 종료해야합니다. 그러나 자식 프로세스가 트랩이나 유사한 메커니즘을 통해 신호를 무시하고 계속할 수있는 경우가 있습니다 를 실행하는 것은 'init'프로세스 (또는 이와 유사한 것)에 의해 상속됩니다. 그러나이 프로세스 동작의 주제는 복잡해질 수 있습니다.

제어 스크립트를 사용하지 않으려는 경우 (다음 설명 참조) 방법 중 하나는 'screen'유틸리티를 사용하여 프로세스를 시작하고 관리하는 것입니다. 'screen'명령은 기능으로 가득하며 마스터하는 데 시간이 걸릴 수 있습니다. 자세한 설명은 'screen'맨 페이지를 읽어 보시기 바랍니다. 백그라운드에서 프로세스를 시작하는 간단한 예는 다음과 같습니다.

화면 -d -m / path / to / program

'스크린'세션 내에서 "/ path / to / program"이 시작됩니다.

다음 명령으로 실행중인 세션을 볼 수 있습니다.

화면 -ls

그리고 언제든지 다음 명령으로 실행중인 프로그램에 다시 연결할 수 있습니다.

화면 -r

그런 다음 ^ C 등으로 종료하십시오.

프로세스를 자유롭게 다시 연결하고 연결을 끊을 수 있다는 것 외에도 'screen'은 프로그램이 생성 할 수있는 stdout ()을 캡처한다는 것입니다.


그러나이 문제에 대한 개인적 선호는 프로세스의 시작과 중지를 관리하는 제어 프로그램을 갖는 것입니다. 이것은 다소 복잡해질 수 있으며 다소 복잡한 스크립팅이 필요합니다. 다른 스크립트와 마찬가지로 수십 가지 좋은 방법이 있습니다. 필자는 일상적으로 응용 프로그램을 시작하고 중지하는 데 사용하는 방법에 대한 bash 예제를 포함 시켰습니다. 작업이 단순하면 제어 스크립트에 직접 삽입하거나이 제어 스크립트가 다른 외부 프로그램을 호출하도록 할 수 있습니다. 이 예제는 프로세스 관리 측면에서 포괄적 인 것은 아닙니다. "start"옵션을 사용할 때 스크립트가 이미 실행되고 있지 않은지 확인하고 실행중인 PID가 실제로 시작한 프로세스인지 확인합니다 (예 : 스크립트가 ' t가 죽고 동일한 PID를 사용하여 다른 프로세스가 시작되었으며 스크립트가 첫 번째 'kill'요청에서 실제로 응답 (종료)되었는지 확인합니다. 이 모든 검사를 수행하면 복잡해질 수 있으며 예제를 너무 길고 복잡하게 만들고 싶지 않았습니다. 쉘 스크립팅을 연습하기 위해 예제를 수정하려고 할 수 있습니다.

다음 코드를 "programctl"파일에 저장하고 명령을 사용하여 실행 가능하게하십시오.

chmod 755 프로그램

그런 다음 파일을 편집하고 "myscript"로 시작하는 사례 섹션에 코드 / 스크립트를 추가하십시오.

"programctl"이 현재 디렉토리에 있다고 가정하면 모든 것이 완료되면 다음을 사용하여 프로그램을 시작할 수 있습니다.

./programctl start

그리고 그것을 중지하십시오 :

./programctl 정지

건배.

#!/bin/bash
# Description:  A wrapper script used to stop/start another script.

#--------------------------------------
# Define Global Environment Settings:
#--------------------------------------

# Name and location of a persistent PID file

PIDFILE="/tmp/tmpfile-$LOGNAME.txt"

#--------------------------------------
# Check command line option and run...
# Note that "myscript" should not
# provided by the user.
#--------------------------------------

case $1
in
    myscript)
        # This is where your script would go.
        # If this is a routine 'bash' shell script, you can enter
        # the script below as illustrated in the example.  
        # Or you could simply provide the path and parameters
        # to another script such as /dir/name/command -options

        # Example of an embedded script:

        while true
        do
            # do something over and over...
            sleep 1
        done

        # Example of an external script:

        /usr/local/bin/longrun -x
    ;;

    start)
        # Start your script in the background.
        # (Note that this is a recursive call to the wrapper
        #  itself that effectively runs your script located above.)
        $0 myscript &

        # Save the backgound job process number into a file.
        jobs -p > $PIDFILE

        # Disconnect the job from this shell.
        # (Note that 'disown' command is only in the 'bash' shell.)
        disown %1

        # Print a message indicating the script has been started
        echo "Script has been started..."
    ;;

    stop)
        # Read the process number into the variable called PID
        read PID < $PIDFILE

        # Remove the PIDFILE
        rm -f $PIDFILE

        # Send a 'terminate' signal to process
        kill $PID

        # Print a message indicating the script has been stopped
        echo "Script has been stopped..."
    ;;

    *)
        # Print a "usage" message in case no arguments are supplied
        echo "Usage: $0 start | stop"
    ;;
esac

나는 당신이 제안한 "스크린"방법을 시도했고 그것은 아름답게 작동합니다. 아직 두 번째 방법을 시도하지 않았습니다. 응답 해주셔서 감사합니다.
light94
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.