Computer >> Máy Tính >  >> Lập trình >> Lập trình BASH

Sử dụng Bash trap trong các tập lệnh của bạn

Thật dễ dàng để phát hiện khi một tập lệnh shell bắt đầu, nhưng không phải lúc nào cũng dễ dàng biết khi nào nó dừng lại. Một tập lệnh có thể kết thúc bình thường, giống như tác giả của nó dự định kết thúc, nhưng nó cũng có thể không thành công do một lỗi nghiêm trọng không mong muốn. Đôi khi, việc bảo tồn phần còn lại của bất cứ thứ gì đang diễn ra khi một tập lệnh bị lỗi sẽ có lợi và những lần khác thì điều đó thật bất tiện. Dù bằng cách nào, việc phát hiện phần cuối của một tập lệnh và phản ứng với nó theo một số cách được tính toán trước là lý do tại sao Bash trap chỉ thị tồn tại.

Phản hồi khi thất bại

Dưới đây là một ví dụ về cách một lỗi trong tập lệnh có thể dẫn đến các lỗi trong tương lai. Giả sử bạn đã viết một chương trình tạo một thư mục tạm thời trong /tmp để nó có thể hủy lưu trữ và xử lý các tệp trước khi nhóm chúng lại với nhau ở một định dạng khác:

#!/usr/bin/env bash
CWD=`pwd`
TMP=${TMP:-/tmp/tmpdir}

## create tmp dir
mkdir "${TMP}"

## extract files to tmp
tar xf "${1}" --directory "${TMP}"

## move to tmpdir and run commands
pushd "${TMP}"
for IMG in *.jpg; do
  mogrify -verbose -flip -flop "${IMG}"
done
tar --create --file "${1%.*}".tar *.jpg

## move back to origin
popd

## bundle with bzip2
bzip2 --compress "${TMP}"/"${1%.*}".tar \
      --stdout > "${1%.*}".tbz

## clean up
/usr/bin/rm -r /tmp/tmpdir

Hầu hết thời gian, kịch bản hoạt động như mong đợi. Tuy nhiên, nếu bạn vô tình chạy nó trên một kho lưu trữ chứa đầy các tệp PNG thay vì các tệp JPEG như mong đợi, nó sẽ không thành công giữa chừng. Một thất bại dẫn đến một thất bại khác, và cuối cùng, tập lệnh thoát ra mà không đạt được chỉ thị cuối cùng để xóa thư mục tạm thời. Miễn là bạn xóa thư mục theo cách thủ công, bạn có thể khôi phục nhanh chóng, nhưng nếu bạn không có mặt để làm điều đó, thì lần sau khi tập lệnh chạy, nó phải xử lý một thư mục tạm thời hiện có chứa đầy các tệp còn sót lại không thể đoán trước.

Một cách để chống lại điều này là đảo ngược và lặp lại logic bằng cách thêm một loại bỏ đề phòng vào đầu tập lệnh. Mặc dù hợp lệ, điều đó dựa vào vũ phu thay vì cấu trúc. Một giải pháp thanh lịch hơn là trap .

Bắt tín hiệu bằng bẫy

trap từ khóa bắt tín hiệu điều đó có thể xảy ra trong quá trình thực hiện. Bạn đã sử dụng một trong những tín hiệu này nếu bạn đã từng sử dụng kill hoặc killall lệnh gọi SIGTERM theo mặc định. Có nhiều tín hiệu khác mà trình bao phản hồi và bạn có thể thấy hầu hết chúng bằng trap -l (như trong "danh sách"):

$ trap --list
 1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL       5) SIGTRAP
 6) SIGABRT      7) SIGBUS       8) SIGFPE       9) SIGKILL     10) SIGUSR1
11) SIGSEGV     12) SIGUSR2     13) SIGPIPE     14) SIGALRM     15) SIGTERM
16) SIGSTKFLT   17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP
21) SIGTTIN     22) SIGTTOU     23) SIGURG      24) SIGXCPU     25) SIGXFSZ
26) SIGVTALRM   27) SIGPROF     28) SIGWINCH    29) SIGIO       30) SIGPWR
31) SIGSYS      34) SIGRTMIN    35) SIGRTMIN+1  36) SIGRTMIN+2  37) SIGRTMIN+3
38) SIGRTMIN+4  39) SIGRTMIN+5  40) SIGRTMIN+6  41) SIGRTMIN+7  42) SIGRTMIN+8
43) SIGRTMIN+9  44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9  56) SIGRTMAX-8  57) SIGRTMAX-7
58) SIGRTMAX-6  59) SIGRTMAX-5  60) SIGRTMAX-4  61) SIGRTMAX-3  62) SIGRTMAX-2
63) SIGRTMAX-1  64) SIGRTMAX

Bất kỳ tín hiệu nào trong số này có thể được dự đoán bằng trap . Ngoài những thứ này, trap nhận ra:

  • EXIT :Xảy ra khi quá trình shell tự thoát ra ngoài
  • ERR :Xảy ra khi một lệnh (chẳng hạn như tar hoặc mkdir ) hoặc lệnh tích hợp (chẳng hạn như pushd hoặc cd ) hoàn thành với trạng thái khác 0
  • DEBUG :Một Boolean đại diện cho chế độ gỡ lỗi

Để đặt bẫy trong Bash, hãy sử dụng trap tiếp theo là danh sách các lệnh bạn muốn được thực hiện, tiếp theo là danh sách các tín hiệu để kích hoạt lệnh đó.

Ví dụ:bẫy này phát hiện một SIGINT , tín hiệu được gửi khi người dùng nhấn Ctrl + C trong khi một quá trình đang chạy:

trap "{ echo 'Terminated with Ctrl+C'; }" SIGINT

Tập lệnh ví dụ có sự cố thư mục tạm thời có thể được khắc phục bằng cách phát hiện bẫy SIGINT , lỗi và thoát thành công:

#!/usr/bin/env bash
CWD=`pwd`
TMP=${TMP:-/tmp/tmpdir}

trap \
 "{ /usr/bin/rm -r "${TMP}" ; exit 255; }" \
 SIGINT SIGTERM ERR EXIT

## create tmp dir
mkdir "${TMP}"
tar xf "${1}" --directory "${TMP}"

## move to tmp and run commands
pushd "${TMP}"
for IMG in *.jpg; do
  mogrify -verbose -flip -flop "${IMG}"
done
tar --create --file "${1%.*}".tar *.jpg

## move back to origin
popd

## zip tar
bzip2 --compress $TMP/"${1%.*}".tar \
      --stdout > "${1%.*}".tbz

Đối với các hành động phức tạp, bạn có thể đơn giản hóa trap câu lệnh với các hàm Bash.

Bẫy trong Bash

Bẫy rất hữu ích để đảm bảo rằng các tập lệnh của bạn kết thúc sạch sẽ, cho dù chúng có chạy thành công hay không. Không bao giờ an toàn khi phụ thuộc hoàn toàn vào việc thu gom rác tự động, vì vậy, đây là một thói quen tốt cần thực hiện nói chung. Hãy thử sử dụng chúng trong các tập lệnh của bạn và xem chúng có thể làm gì!