문제

문맥:

EXIT 의사 신호에 대한 트랩과 하위 쉘이 포함된 bash 스크립트가 있는데, 이 스크립트는 실행 중에 인터럽트를 제대로 트래핑하지 않습니다. rsync.예는 다음과 같습니다.

#!/bin/bash
logfile=/path/to/file;
directory1=/path/to/dir
directory2=/path/to/dir

cleanup () {
     echo "Cleaning up!"
     #do stuff
     trap - EXIT 
}

trap '{
    (cleanup;) | 2>&1 tee -a $logfile
}' EXIT

(
    #main script logic, including the following lines:
    (exec sleep 10;);        
    (exec rsync --progress -av --delete $directory1 /var/tmp/$directory2;);

)  | 2>&1 tee -a $logfile
trap - EXIT #just in case cleanup isn't called for some reason

스크립트의 아이디어는 다음과 같습니다.대부분의 중요한 로직은 파이프로 연결된 서브셸에서 실행됩니다. tee 로그 파일에 저장하므로 그럴 필요가 없습니다. tee 모든 내용을 기록하려면 기본 논리의 모든 줄을 확인하세요.서브쉘이 종료되거나 어떤 이유로든 스크립트가 중지될 때마다(EXIT 의사 신호는 이러한 모든 경우를 캡처해야 함) 트랩은 이를 가로채서 다음을 실행합니다. cleanup() 기능을 수행한 후 트랩을 제거하십시오.그만큼 rsync 그리고 sleep 명령(sleep은 단지 예일 뿐임)은 다음을 통해 실행됩니다. exec 실행 중인 상위 스크립트를 종료하면 좀비 프로세스가 생성되는 것을 방지하기 위해 잠재적으로 장기 실행되는 각 명령은 자체 하위 쉘에 래핑됩니다. exec 완료되면 전체 스크립트가 종료되지 않습니다.

문제:

스크립트를 중단하면 (를 통해 kill 또는 CTRL+C) exec/subshell 래핑 중 sleep 명령을 실행하면 트랩이 제대로 작동하고 "정리 중!" 에코가 표시되고 기록됩니다.도중에 스크립트를 중단하면 rsync 명령, 알겠습니다 rsync 끝내고 쓰세요 rsync error: received SIGINT, SIGTERM, or SIGHUP (code 20) at rsync.c(544) [sender=3.0.6] 화면에 표시되고 스크립트가 종료됩니다.정리도, 트래핑도 없습니다.왜 방해/살해가 되지 않는가? rsync 함정을 발동시키나요?

나는 --no-detach rsync로 전환했지만 아무것도 변경되지 않았습니다.bash 4.1.2, rsync 3.0.6, centOS 6.2가 있습니다.

도움이 되었습니까?

해결책

X 지점의 모든 출력을 모든 곳에서 반복하고 모든 하위 쉘과 실행 파일을 엉망으로 만들 필요 없이 티로 리디렉션하는 것은 어떻습니까?(내가 뭔가를 놓치지 않았으면 좋겠어)

#!/bin/bash
logfile=/path/to/file;
directory1=/path/to/dir
directory2=/path/to/dir

exec > >(exec tee -a $logfile) 2>&1

cleanup () {
     echo "Cleaning up!"
     #do stuff
     trap - EXIT 
}
trap cleanup EXIT

sleep 10
rsync --progress -av --delete $directory1 /var/tmp/$directory2

다른 팁

게다가 set -e, 내 생각엔 네가 원하는 것 같아 set -E:

설정된 경우 ERR의 모든 트랩은 셸 기능, 명령 대체 및 하위 셸 환경에서 실행되는 명령에 의해 상속됩니다.이러한 경우 ERR 트랩은 일반적으로 상속되지 않습니다.

또는 하위 쉘에서 명령을 래핑하는 대신 중괄호를 사용하면 명령 출력을 리디렉션할 수 있지만 현재 쉘에서 실행됩니다.

트랩에 INT를 추가하면 인터럽트가 제대로 포착됩니다.

trap '{
    (cleanup;) | 2>&1 tee -a $logfile
}' EXIT INT

Bash는 인터럽트를 올바르게 트래핑하고 있습니다.그러나 이는 스크립트가 종료 시 트랩되는 이유에 대한 질문에 대한 답변은 아닙니다. sleep 중단되었거나 왜 트리거되지 않는지 rsync, 그러나 스크립트가 예상대로 작동하도록 만듭니다.도움이 되었기를 바랍니다.

오류 발생 시 종료되도록 쉘이 구성되었을 수 있습니다.

bash # enter subshell
set -e
trap "echo woah" EXIT
sleep 4

당신이 방해한다면 sleep (^C) 그러면 서브쉘은 다음으로 인해 종료됩니다. set -e 인쇄하고 woah 진행중.

또한 약간 관련이 없습니다.당신의 trap - EXIT (명시적으로) 서브셸에 있으므로 정리 함수가 반환된 후에는 효과가 없습니다.

실험을 통해 확실히 알 수 있는 것은 rsync 다음과 같은 다른 도구처럼 동작합니다. ping 호출하는 Bash 부모로부터 신호를 상속받지 않습니다.

따라서 약간의 창의력을 발휘하여 다음과 같은 작업을 수행해야 합니다.

$ cat rsync.bash
#!/bin/sh

 set -m
 trap '' SIGINT SIGTERM EXIT
 rsync -avz LargeTestFile.500M root@host.mydom.com:/tmp/. &
 wait

 echo FIN

이제 실행하면 다음과 같습니다.

$ ./rsync.bash
X11 forwarding request failed
building file list ... done
LargeTestFile.500M
^C^C^C^C^C^C^C^C^C^C
sent 509984 bytes  received 42 bytes  92732.00 bytes/sec
total size is 524288000  speedup is 1027.96
FIN

그리고 파일이 완전히 전송되었음을 확인할 수 있습니다.

$ ll -h | grep Large
-rw-------. 1  501 games 500M Jul  9 21:44 LargeTestFile.500M

작동 원리

여기서 비결은 Bash에게 다음을 통해 알리는 것입니다. set -m 그 안에 있는 모든 백그라운드 작업에 대한 작업 제어를 비활성화합니다.그런 다음 배경을 설정합니다. rsync 그런 다음 wait 마지막 실행 명령을 기다리는 명령, rsync, 완료될 때까지.

그런 다음 전체 스크립트를 다음과 같이 보호합니다. trap '' SIGINT SIGTERM EXIT.

참고자료

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top