Shell-Script
sigterm 上奇怪的 aws 同步行為
這對我來說是莫名其妙的行為。在執行 aws s3 sync 命令時,我向腳本發送了終止信號,儘管我處理了 sigterm 錯誤,但錯誤陷阱也由 aws sync 命令觸發,我不明白為什麼。更令人困惑的是,該命令會引發錯誤並繼續:
腳本:
#! /bin/bash trap 'echo GOT ERROR, exiting' ERR trap 'echo GOT SIGTERM!' SIGTERM while true; do date +%F_%T aws s3 cp /vagrant/audio/ s3://testarchive/tester/ --recursive sleep 1 done
執行腳本的命令:
timeout 5s ./tester.sh
輸出:
upload: ../../vagrant/audio/2019-09-16/3/35322118-8264-406B-961B-EAF1FE7A34EF.wav to s3://testarchive/tester/2019-09-16/3/35322118-8264-406B-961B-EAF1FE7A34EF.wav upload: ../../vagrant/audio/2019-09-16/1/165BD3D0-773A-4591-A43E-D67810716066.wav to s3://testarchive/tester/2019-09-16/1/165BD3D0-773A-4591-A43E-D67810716066.wav upload: ../../vagrant/audio/2019-09-16/2/2A9559BB-168A-47D2-943A-A51B7885233B.wav to s3://testarchive/tester/2019-09-16/2/2A9559BB-168A-47D2-943A-A51B7885233B.wav Terminated6.8 MiB/123.1 MiB (1.5 MiB/s) with 422 file(s) remaining GOT ERROR, exiting GOT SIGTERM! 2020-01-17_21:05:40 upload: ../../vagrant/audio/2019-09-16/0/07502A17-9304-4995-94E1-A1B0D439EEE7.wav to s3://testarchive/tester/2019-09-16/0/07502A17-9304-4995-94E1-A1B0D439EEE7.wav upload: ../../vagrant/audio/2019-09-16/0/05E4C765-C2FA-4EC0-9803-8FF02C0FEDDE.wav to s3://testarchive/tester/2019-09-16/0/05E4C765-C2FA-4EC0-9803-8FF02C0FEDDE.wav upload: ../../vagrant/audio/2019-09-
編輯#2:
29 1 * * * root strace -e trace=kill timeout --foreground 6 /home/vagrant/tester.sh &> /home/vagrant/tester.log
#! /bin/bash trap 'echo GOT ERROR..' ERR trap 'echo GOT SIGTERM! && set_terminate_flag' SIGTERM terminate_flag=false function set_terminate_flag { terminate_flag=true } while true; do if [ "$terminate_flag" = true ]; then echo OMG IT WORKS! exit 0 fi date +%F_%T aws s3 cp /vagrant/audio/ s3://testarchive/tester/ --recursive echo LOOP IS Done, begin sleep done
輸出:
...(skip output, 6 seconds have passed!!!) --- SIGALRM {si_signo=SIGALRM, si_code=SI_TIMER, si_timerid=0, si_overrun=0, si_value={int=14831664, ptr=0xe25030}} --- kill(9432, SIGTERM) = 0 kill(9432, SIGCONT) = 0 ...(skip output) upload: ../vagrant/audio/2020-01-01/E7914F83-8A89-4679-ABBC-8DB261D13349-01.wav to s3://testarchive/tester/2020-01-01/E7914F83-8A89-4679-ABBC-8DB261D13349-01.wav GOT SIGTERM! LOOP IS Done, begin sleep OMG IT WORKS! --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=9432, si_uid=0, si_status=0, si_utime=0, si_stime=0} --- +++ exited with 124 +++
trap 'echo GOT ERROR, exiting' ERR
簡單地說“退出”並不意味著它也是真的;-)
ERR
每當命令失敗時都會執行陷阱,無論腳本是否在之後立即退出(例如,因為set -e
):$ bash -c 'trap "echo error, not exiting yet" ERR; false; echo DONE' error, not exiting yet DONE
在您的情況下,失敗的命令可能是
date
oraws
,但很可能是sleep
(這是外部命令,而不是內置命令)。sleep
以非零狀態退出(=失敗,因此ERR
觸發陷阱),因為它也被發送的信號殺死timeout
:timeout
首先向其子程序發送信號,然後向其所屬的整個程序組發送信號:$ strace -e trace=kill timeout 1s bash -c 'echo $$; while :; do sleep 3600; done ' 4851 ... kill(4851, SIGTERM) = 0 kill(0, SIGTERM) = 0 ...
直到它等待的前台命令退出後, shell 才會執行任何陷阱;如果
timeout
沒有向整個程序組發出信號(可以通過該--foreground
選項實現),則該前台命令可能不會退出,並且陷阱可能不會執行:$ timeout 1s bash -c 'trap "echo TERM caught" TERM; sleep 36000; echo DONE' Terminated TERM caught DONE $ timeout --foreground 1s bash -c 'trap "echo TERM caught" TERM; sleep 36000; echo DONE' <wait and wait>