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

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

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개 종료. 명령줄에서 스크립트를 실행하면 2개의 프로세스가 시작되기 때문에 이는 중요합니다.스크립트 자체2,inotify 프로세스.

답변1

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

ps -aux | grep script_name
killall script_name inotifywait

아니면 한 줄로 모두 수행하세요.

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

답변2

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

# jobs

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

# fg 1 

여기에 이미지 설명을 입력하세요.

프론트 데스크로 모셔다 드립니다.

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

ps -aux | grep script_name

여기에 이미지 설명을 입력하세요.

그런 다음 pid를 사용하여 죽이십시오.

sudo kill -9 pid_number_here

답변3

아시다시피, 이를 수행하는 방법에는 여러 가지가 있습니다.

"업데이트 #2" 관련 - 일반적으로 상위-하위 계층 구조에서 프로세스를 종료하면 일반적으로 관련된 모든 프로세스가 종료됩니다. 그러나 많은 예외가 있습니다. 이상적으로는 프로세스 트리의 마지막 "하위 프로세스"를 종료하고 하위 프로세스에 실행할 다른 작업이 없으면 하위 프로세스의 상위 프로세스가 종료되어야 합니다. 그러나 상위 프로세스를 종료하면 상위 프로세스가 종료되면 신호가 하위 프로세스로 전달되고 하위 프로세스도 종료되어야 합니다. 그러나 경우에 따라 하위 프로세스가 트랩 또는 유사한 메커니즘을 통해 신호를 무시할 수 있습니다. ) 계속 실행될 수 있으며 "init" 프로세스(또는 유사한 프로세스)에 의해 상속됩니다. 하지만 프로세스 동작에 대한 이 주제는 복잡해질 수 있으므로 그대로 두겠습니다.

제어 스크립트(아래 설명)를 사용하고 싶지 않은 경우 제가 선호하는 한 가지 방법은 "스크린" 유틸리티를 사용하여 프로세스를 시작하고 관리하는 것입니다. "screen" 명령은 기능이 풍부하므로 익히는 데 시간이 걸릴 수 있습니다. 완전한 설명을 보려면 "screen" 매뉴얼 페이지를 읽어보시기 바랍니다. 백그라운드에서 프로세스를 시작하는 간단한 예는 다음 명령입니다.

화면 -d -m /경로/to/프로그램

그러면 "screen" 세션 내에서 "/path/to/program"이 시작됩니다.

다음 명령을 사용하여 실행 중인 세션을 볼 수 있습니다.

스크린-ls

다음 명령을 사용하면 언제든지 실행 중인 프로그램에 다시 연결할 수 있습니다.

스크린-R

그런 다음 ^C 또는 다른 것으로 종료하십시오.

프로세스에 마음대로 다시 연결하고 연결을 끊을 수 있다는 이점 외에도 "스크린"은 프로그램이 생성할 수 있는 모든 stdout()을 캡처합니다.


하지만 이 문제에 있어서 제가 개인적으로 선호하는 것은 프로세스의 시작과 중지를 관리하는 제어 프로그램을 갖는 것입니다. 이는 약간 복잡해질 수 있으며 틀림없이 복잡한 스크립팅이 필요합니다. 모든 스크립트와 마찬가지로 이를 구현하는 좋은 방법이 많이 있습니다. 애플리케이션을 시작하고 중지하는 데 자주 사용하는 방법에 대한 bash 예제를 제공했습니다. 작업이 간단한 경우 제어 스크립트에 직접 삽입하거나 제어 스크립트가 다른 외부 프로그램을 호출하도록 할 수 있습니다. 이 예는 관리 프로세스 측면에서 결코 포괄적이지 않다는 점에 유의하십시오. 나는 다음 시나리오의 가능성을 무시하고 있습니다. "시작" 옵션을 사용할 때 스크립트가 이미 실행되고 있지 않은지 확인하고, 실행 중인 PID가 실제로 시작한 프로세스인지 확인하십시오(예: 스크립트가 종료되지 않았고 다른 PID가 종료되지 않았는지 확인). 프로세스가 이미 동일한 PID 시작을 사용하고 있음) 스크립트가 첫 번째 "종료" 요청에 실제로 응답(종료)하는지 확인하세요. 이러한 모든 검사를 수행하는 것은 복잡해질 수 있으므로 예제가 너무 길고 복잡해지는 것을 원하지 않습니다. 쉘 스크립팅을 연습하기 위해 예제를 수정하고 싶을 수도 있습니다.

다음 코드를 "programctl"이라는 파일에 저장하고 다음 명령을 사용하여 실행 가능하게 만듭니다.

chmod 755 프로그램 제어

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

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

./programctl 시작

중지하세요.

./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

답변4

ps+ grep또는를 사용하여 pgrep프로세스를 얻을 수 있습니다이름/PID; 나중에 killall/를 사용하여 pkill프로세스 이름을 삭제하거나 killpid를 삭제합니다. 아래의 모든 것이 작동해야 합니다.

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프로세스 이름을 인쇄할 수도 있습니다.

관련 정보