bash 의 신호 처리 메커니즘

11891 단어 shellbashlinuxsignal
Linux 의 신호
신호 Signal 는 운영 체제 에서 자주 사용 하 는 프로 세 스 통신 수단 으로 주로 특정한 사건 의 발생 을 묘사 하 는데 프로 세 스 가 신 호 를 받 을 때 다음 과 같은 몇 가지 처리 방식 이 있다.
  • 캡 처 및 사용자 정의 처리 함수: signal 시스템 에 사용자 정의 반전 함 수 를 호출 합 니 다. 프로 세 스 는 신 호 를 받 을 때 이 반전 함 수 를 실행 합 니 다.
  • 신호 무시: signal 시스템 호출 전달 SIG_IGN, 커 널 은 이 신 호 를 직접 버 리 기 때문에 목표 프로 세 스 는 이 신 호 를 받 지 못 합 니 다.
  • 기본 동작 을 수행 합 니 다. 커 널 은 모든 신호 에 대해 기본 적 인 처리 방식 을 정 의 했 습 니 다. 신호 에 무시 하거나 사용자 정의 처리 함 수 를 설정 하면 signal 시스템 호출 전송 SIG_DFL 에 이 신호 처리 방식 을 기본 값 으로 복원 할 수 있 습 니 다.
  • signal(SIGINT, SIG_IGN);  //     
    signal(SIGTERM, SIG_DFL);  //     
    signal(SIGSTOP, m_handler);  //      
    Linux 에서 신호 의 전송 은 sigqueue, kill, raise 시스템 호출 에 의존 하고 신호 의 처리 상 태 는 목표 프로 세 스 task_structsignal 변수 에 기록 되 어 있 으 며 이 변수의 유형 은 sigset_t 이 고 한 사람 당 하나의 신 호 를 저장 하 는 처리 상태 이기 때문에 신호 비트 맵 signal bitmap 이 라 고도 불 린 다. 발생 generate 과 배달 delivery 에 있다.사이 의 신호 상 태 는 미결 pending 로 표 시 됩 니 다. 목표 프로 세 스 가 짧 은 시간 에 대량의 중복 신 호 를 받 거나 sigpending 시스템 호출 이 특정한 신 호 를 막 을 때 목표 프로 세 스 신호 비트 맵 에서 이 신호 의 상 태 는 미결 로 변 합 니 다. Linux 5.3.0 에서 미결 상태 에 있 는 신호 에 대해 두 가지 처리 전략 이 있 습 니 다.
  • 버 림: 대상 프로 세 스에 서 특정한 신호 의 상태 가 미결 이거 나 무시 되면 커 널 은 이 신호 의 상태 가 바 뀔 때 까지 모든 신 호 를 버 립 니 다. 이것 은 초기 Unix 시스템 의 처리 전략 입 니 다. 호환성 을 확보 하기 위해 Linux 5.3.0 에서 번호 가 1-31 인 신 호 는 버 림 처리 전략 을 따 릅 니 다. 즉, 사용 sigqueue이 신 호 를 보 내 도 줄 을 서지 않 습 니 다. 신 호 를 잃 어 버 릴 가능성 이 있 기 때문에 전략 에 따라 처리 하 는 신 호 를 믿 을 수 없 는 신호 라 고 부 릅 니 다. POSIX 에 따라 비 실시 간 신호 라 고 부 릅 니 다.
  • 줄 서기: Linux 에서 신호 처리 방식 을 개 선 했 습 니 다. 커 널 은 목표 프로 세 스 task_struct 에서 신호 대기 열 을 유지 합 니 다. 커 널 이 신 호 를 받 았 고 목표 프로 세 스 에서 이 신호 상태 가 미결 이면 새로 발생 한 신 호 를 목표 프로 세 스 의 신호 대기 열 에 넣 습 니 다.이렇게 걸 려 있 는 신호 개수 가 커 널 이 설정 한 상한 선 을 초과 하지 않 으 면 이론 적 으로 잃 어 버 리 지 않 는 다. Linux 5.3.0 에서 번호 32-64 의 신 호 는 줄 서기 처리 전략 을 따 르 기 때문에 신뢰성 있 는 신호 라 고도 불 린 다. POSIX 에 따 르 면 실시 간 신호 라 고 불 린 다.
  • 상용 신호
    대부분의 Linux 발행 판 은 man 7 signal 을 통 해 현재 시스템 에서 지원 하 는 신호 종 류 를 볼 수 있 고 kill -l 모든 신호 와 해당 하 는 숫자 를 볼 수 있 습 니 다. 그 중에서 우리 가 자주 사용 하 는 것 은:
  • (2) SIGINT: 프론트 데스크 에 있 는 실행 중인 프로 세 스에 보 내 는 키보드 인 터 럽 트 신호, 종료 interrupt, 일반 대응 Ctrl + C.
  • (19) SIGSTOP: 무시 할 수 없 는 정지 신 호 는 프로 그래 밍 방식 으로 보 내 는 신호 입 니 다.
  • (20) SIGTSTP: 정지 신호, 현재 퀘 스 트 stop 를 백 스테이지 에 올 리 고 통제 권 을 shell 에 게 넘 기 며 일반 대응 Ctrl + Z
  • (9) SIGKILL: 차단 되 거나 처리 되 거나 무시 되 는 신 호 는 보통 특정한 프로 세 스 를 강제로 죽 이 는 데 사 용 됩 니 다. kill -9
  • (15) SIGTERM: 프로그램 종료 terminate 신 호 는 SIGKILL 와 달리 이 신 호 는 차단 되 고 처 리 될 수 있 습 니 다. 보통 프로그램 이 정상적으로 종료 하도록 요구 합 니 다. shell 명령 kill 이 부족 하면 이 신 호 를 발생 시 킵 니 다.
  • (14) SIGALRM :
  • (1) SIGHUP: 이 신 호 는 사용자 단말기 연결 (정상 또는 비정 상) 이 끝 날 때 보 냅 니 다. 보통 터미널 의 제어 프로 세 스 가 끝 날 때 같은 session 안의 각 작업 을 알 립 니 다. 이 때 는 제어 단말기 와 더 이상 연결 되 지 않 습 니 다.로그 인 Linux 시 시스템 은 로그 인 사용자 에 게 터미널 Session 을 할당 합 니 다.이 터미널 에서 실행 되 는 모든 프로그램 은 프론트 프로 세 스 그룹 과 백 엔 드 프로 세 스 그룹 을 포함 하여 일반적으로 이것 Session 에 속 합 니 다.사용자 가 로그 인 Linux 을 종료 하면 프론트 데스크 톱 프로 세 스 그룹 과 배경 에 터미널 출력 프로 세 스 가 있 습 니 다 SIGHUP 신 호 를 받 습 니 다.이 신호 의 기본 동작 은 프로 세 스 를 종료 하 는 것 입 니 다. 따라서 프론트 프로 세 스 그룹 과 백 엔 드 에 터미널 출력 이 있 는 프로 세 스 가 중 단 됩 니 다.터미널 과 관 계 를 끊 은 데 몬 에 대해 이 신 호 는 설정 파일 을 다시 읽 는 것 을 알 리 는 데 사 용 됩 니 다.

  • bash 에서 신호 처리bash 의 전형 적 인 응용 장면 은 내 장 된 명령 kill 을 통 해 지정 한 프로 세 스에 신 호 를 보 내 고 기본 값 으로 SIGTERM 신 호 를 보 내 는 것 입 니 다. 예 를 들 어 모든 이름 chrome 의 프로 세 스 를 종료 합 니 다.
    > kill `pgrep chrome`
    > killall chrome
    > kill `ps -ef | grep chrome | awk '{ print $2 }'`
    > kill `pidof chrome`

    그 밖 에 trap 신 호 를 포착 하여 특정한 신호 에 대한 처 리 를 실현 할 수 있 는데 그 문법 은 다음 과 같다.
    trap [COMMANDS] [SIGNALS]
    trap 신 호 를 포착 한 후에 설 정 된 명령 을 실행 합 니 다. 이 명령 은 유효한 Linux 명령 이나 사용자 정의 함수 일 수 있 습 니 다. shell 스 크 립 트 에서 trap 종료 할 때 임시 파일 을 지 울 수 있 습 니 다. 예 를 들 어:
    #!/bin/bash
    tempfile=$(mktemp) || exit
    trap 'rm -f "$tempfile"' EXIT

    또 다른 전형 적 인 용법 은 데 몬 에서 캡 처 SIGHUP 하고 프로필 을 다시 읽 는 것 입 니 다. 예 를 들 어:
    #!/usr/bin/bash
    
    if [ ! -r "$1" ]; then
        echo "Usage: $0 "
        exit
    fi
    
    echo "PID: $$"
    
    CONFIG=$1
    
    read_config () { 
        echo "reading cfg from $CONFIG"
        source "$CONFIG"
    }
    
    read_config
    trap "read_config" HUP
    
    while :
    do
        echo "$var"
        sleep 15
    done

    다음 에 우 리 는 두 단말기 에서 테스트 를 진행 할 수 있다.
    #    
    > bash remove_temp.sh ./config/cfg1 
    PID: 8807
    reading cfg from ./config/cfg1
    from cfg1
    reading cfg from ./config/cfg1
    after change
    
    #    
    > cat > cfg1 << EOF
    var="after change"
    EOF
    > kill -s HUP 8807
    trap 명령 을 통 해 신 호 를 저장 하고 재 설정 할 수 있 습 니 다. 예 를 들 어:
    > trap "printf BOOM" INT
    > ^CBOOM
    > traps=$(trap)  #         
    > trap INT  #            
    > ^C
    > eval $traps  #         
    > ^CBOOM
    trap 여러 개의 신 호 를 포착 하 는 것 도 지원 한다. 예 를 들 어:
    #!/usr/bin/bash
    
    trap "echo Boom!" SIGINT SIGTERM
    
    echo $PPID $$
    while : #               
    do
        sleep 60
    done
    trap 대소 문자 에 민감 하지 않 으 며 접두사 SIG 를 무시 할 수 있 습 니 다. 아래 의 표기 법 은 등가 입 니 다.
    trap "echo 123" SIGINT
    trap "echo 123" INT 
    trap "echo 123" 2
    trap "echo 123" int 
    trap "echo 123" Int

    특수 한 상황bash 외부 명령 을 수행 할 때 프론트 데스크 톱 임무 의 신호 처리 우선 순 위 를 높 일 수 있 습 니 다. 현재 데스크 톱 임무 가 수행 되 거나 중지 되 었 을 때 bash 방금 받 은 신 호 를 처리 할 수 있 습 니 다. 다음 과 같 습 니 다.
    #    
    > sleep 100  #        
    #     ...
    
    >  # 100                
    
    #    
    #          
    > pstree -ap 16003
    bash,16003
      `-sleep,17249 100  #            
    > kill -s INT 16003  #       bash     

    그러나 주의해 야 할 것 은 shell 에서 사용 Ctrl + C 하면 전체 프로 세 스 그룹 에 SIGINT 을 보 낼 수 있 기 때문에 상례 에서 터미널 1 에서 사용 Ctrl + C 하면 sleep 즉시 종료 되 고 빈 줄 을 인쇄 할 수 있 습 니 다. 또한 프론트 데스크 톱 임 무 를 백 스테이지 에 놓 아서 bash 신 호 를 우선 처리 할 수 있 습 니 다. 그러나 bash 종료 할 때 완성 되 지 않 은 백 스테이지 임무 가 있 으 면이 작업 들 은 고아 프로 세 스 로 변 하고 부모 프로 세 스 는 PID=1 프로 세 스 로 변 합 니 다.
    > (sleep 50 & sleep 50 & wait)
    #    
    bash,15158
      `-bash,7629
          |-sleep,7630 50
          `-sleep,7631 50
    > kill 7629
    #    
    bash,15158
    > ps -ef | grep "sleep 50"
    remilia  11168     1  0 16:56 pts/2    00:00:00 sleep 50
    remilia  11169     1  0 16:56 pts/2    00:00:00 sleep 50
    #      PPID,      1  

    프로 세 스 가 종료 되 었 을 때 배경 작업 도 종료 하려 면 배경 작업 init 을 기록 하고 종료 하기 전에 이 프로 세 스 PID 를 종료 해 야 합 니 다.
    #!/usr/bin/bash
    
    BPIDARRAY=()
    
    for i in {0..9}; do
      sleep 20 &
      BPIDARRAY[$i]=$!
    done
    sleep 3
    trap "kill `echo ${BPIDARRAY[@]}`" EXIT
    wait

    기타 용법kill 정 의 된 신호 명 이나 수 치 를 포착 할 수 있 을 뿐만 아니 라 다음 과 같은 용법 도 지원 한다.
  • trap: 와 유사 하여 현재 시스템 이 지원 하 는 모든 신 호 를 표시 합 니 다.
  • trap -l 또는 kill -l: trap 을 통 해 설 치 된 신호 처리 명령 을 보 여 줍 니 다.
  • > trap -p
    trap -- 'code' EXIT
    trap -- 'echo SIGINT' SIGINT
  • trap -p: trap 에서 만 사용 할 수 있 는 번호 trap "some code" EXIT 의 특수 신 호 는 shell 에서 모든 탈퇴 상황 을 대표 하고 표준 0 에 서 는 포착 bash 에 사용 된다.
  • > trap "code" EXIT
    > ^D  #            vscode
  • shell: 오류 가 발생 한 명령 을 캡 처 하고 명령 실행 에 오류 가 발생 했 을 때 미리 정 의 된 코드 블록 을 실행 합 니 다.
  • exit: 디 버 깅 모드 로 명령 을 실행 할 때 각 명령 이 실행 되 기 전에 미리 정 의 된 코드 블록 을 실행 합 니 다.
  • 주의 사항trap "some code" ERR 설정 은 현재 프로 세 스에 만 적 용 됩 니 다. 따라서 trap "some code" DEBUG 또는 trap 을 통 해 실 행 된 스 크 립 트 를 제외 하고 . 현재 source 설정 을 계승 하지 않 습 니 다 child shell.
    > trap "printf book" 2
    > ^Cbook
    > bash -c "trap -p"  #    
    > bash
    > ^C  #       

    함수 에 설 치 된 shell 도 전역 적 으로 유효 합 니 다. 같은 신 호 를 중복 설정 하면 마지막 trap 만 유효 합 니 다. 특히 주의해 야 할 것 은 trap 스 크 립 트 나 비 상호작용 trap 에서 캡 처 bashbash shell 할 때 다음 과 같은 방식 으로 하 는 것 이 좋 습 니 다.
    trap 'rm -f "$tempfile"; trap - INT; kill -s INT "$$"' INT
    SIGINT 종료 신 호 를 받 을 때 SIGQUIT 원칙 에 따라 처리 하고 bash 을 누 를 때 현재 프로 세 스 팀 은 WCE (wait and cooperative exit) 을 받 습 니 다. 그러면 다음 과 같은 몇 가지 상황 이 있 습 니 다 (신 호 를 무시 하 는 상황 을 고려 하지 않 습 니 다).
  • 프론트 데스크 톱 프로 세 스 처리 Ctrl + C:
  • 신 호 를 처리 하고 자신 SIGINT 을 처리 하면 부모 SIGINT (호출 자) 는 하위 프로 세 스 가 신 호 를 통 해 비정 상 으로 종료 되 는 것 을 받 고 현재 스 크 립 트 를 즉시 종료 합 니 다.
  • 신 호 를 처리 하고 kill 정상적으로 종료 하면 부모 bash (호출 자) 는 하위 프로 세 스 가 정상적으로 실행 되 었 다 고 생각 하고 스 크 립 트 를 계속 설명 합 니 다.
  • 프론트 데스크 톱 프로 세 스 가 처리 되 지 않 음 exit: 이 경우 신 호 를 처리 하고 자신 bash 과 비슷 합 니 다. 부모 SIGINT (호출 자) 는 현재 스 크 립 트 를 즉시 종료 합 니 다.
  • 예 를 들 어 다음 스 크 립 트 를 고려 해 보 세 요.
    > cat ping_loop.sh
    for i in  `seq 254`;  do
        ping -c 2 "192.168.1.$i"
    done
    
    > bash ping_loop.sh
    #       ,      254   Ctrl + C       
    #       bash    

    상례 에서 kill 를 누 르 면 bash 먼저 Ctrl + C 를 받 고 처리 한 다음 에 정상적으로 탈퇴 한다. 그 다음 에 pingSIGINT 와 이전 명령 bash 의 탈퇴 상 태 를 받 고 정상 적 인 탈퇴 를 발견 하면 그 다음 명령 을 계속 설명 한다. SIGINT 이러한 ping 192.168.0.1 신호 에 대해 기본 적 으로 처리 하 라 는 명령 은 상황 이 완전히 다르다.
    > cat sleep_loop.sh
    i=1
    while [ "$i" -le 100 ]; do
      printf "%d " "$i"
      i=$((i+1))
      sleep 10
    done
    echo
    
    > bash sleep_loop.sh
    #       ,     Ctrl + C        

    상례 에서 sleep 를 누 르 면 SIGINT 먼저 Ctrl + C 를 받 고 기본 적 인 방식 으로 처리 한 다음 에 sleepSIGINT 와 이전 명령 bash 의 탈퇴 상 태 를 받 게 되 고 SIGINT 비정 상 탈퇴 를 발견 하면 sleep 10 즉시 탈퇴 할 수 있 습 니 다. 우 리 는 더욱 간단 한 명령 을 통 해 이해 할 수 있 습 니 다.
    > (ping 192.168.0.1; ping 192.168.0.2)
    bash,7744  
     `-bash,24002  
         `-ping,24011 192.168.0.1
    
    > kill -2 24011 24002  #         
    #    ping     SIGINT     0,         
    # bash 24002    ping 24026             
    #           
    bash,7744  
     `-bash,24002
         `-ping,24026 192.168.0.2
    
    > (sleep 50; sleep 50)
    bash,7744
      `-bash,26053
          `-sleep,26054 50
    > kill -2 26054 26053
    # sleep          SIGINT   
    #    bash 26053          SIGINT         
    # bash 26053      

    참고 내용
    Signal Trap How "Exit Traps" Can Make Your Bash Scripts Way More Robust And Reliable

    좋은 웹페이지 즐겨찾기