trừu tượng
Mã chính xác phải là:
#!/bin/sh
[ "$#" -eq 0 ] && echo "Usage: $0 command [args]" && exit 1
[ "$(date -d tomorrow +'%d')" = 01 ] || exit 0
exec "$@"
Gọi tập lệnh này end_of_month.sh
và cuộc gọi trong cron chỉ đơn giản là:
00 12 28-31 * * /path/to/script/end_of_month.sh command
Điều đó sẽ chạy tập lệnh end_of_month
(trong nội bộ sẽ kiểm tra xem ngày đó là ngày cuối cùng của tháng) chỉ vào các ngày 28, 29, 30 và 31. Không cần kiểm tra cuối tháng vào bất kỳ ngày nào khác.
Bài cũ.
Đó là một trích dẫn từ cuốn sách "Dòng lệnh Linux và Kinh thánh Shell Scripting" của Richard Blum, Christine Bresnahan Trang 442, Ấn bản thứ ba, John Wiley & Sons © 2015.
Vâng, đó là những gì nó nói, nhưng đó là sai / không đầy đủ:
- Thiếu một đóng cửa
fi
.
- Cần không gian giữa
[
và sau đây `
.
- Nó được mạnh mẽ khuyến khích sử dụng $ (...) thay vì
`…`
.
- Điều quan trọng là bạn sử dụng các trích dẫn xung quanh việc mở rộng như
"$(…)"
- Có thêm
;
sauthen
Làm sao tôi biết? (tốt, theo kinh nghiệm) nhưng bạn có thể thử Shellcheck . Dán mã từ cuốn sách (sau dấu hoa thị) và nó sẽ hiển thị cho bạn các lỗi được liệt kê ở trên cộng với "thiếu shebang". Một tập lệnh không có bất kỳ lỗi nào trong Shellcheck là:
#!/bin/sh
if [ "$(date +%d -d tomorrow)" = 01 ] ; then script.sh; fi
Trang web đó hoạt động vì những gì được viết là "mã vỏ". Đó là một cú pháp hoạt động trong nhiều shell.
Một số vấn đề mà shellcheck không đề cập đến là:
Giả sử lệnh ngày là phiên bản ngày của GNU. Một với một -d
lựa chọn chấp nhận tomorrow
như một giá trị (busybox có một tùy chọn -d nhưng không hiểu ngày mai và BSD có một -d
lựa chọn nào khác không liên quan đến "hiển thị" thời gian).
Tốt hơn là đặt định dạng sau tất cả các tùy chọn date -d tomorrow +'%d'
.
Thời gian bắt đầu cron luôn theo giờ địa phương, có thể khiến một công việc bắt đầu sớm hơn 1 giờ so với số ngày chính xác nếu DST (thời gian tiết kiệm ánh sáng ban ngày) được đặt hoặc không được đặt.
Những gì chúng tôi đã thực hiện là một kịch bản shell có thể được gọi bằng cron. Chúng ta có thể sửa đổi thêm tập lệnh để chấp nhận các đối số của chương trình hoặc lệnh để thực thi, như thế này (cuối cùng, mã chính xác):
#!/bin/sh
[ "$#" -eq 0 ] && echo "Usage: $0 command [args]" && exit 1
[ "$(date -d tomorrow +'%d')" = 01 ] || exit 0
exec "$@"
Gọi tập lệnh này end_of_month.sh
và cuộc gọi trong cron chỉ đơn giản là:
00 12 28-31 * * /path/to/script/end_of_month.sh command
Điều đó sẽ chạy tập lệnh end_of_month
(trong nội bộ sẽ kiểm tra xem ngày đó là ngày cuối cùng của tháng) chỉ vào các ngày 28, 29, 30 và 31. Không cần kiểm tra cuối tháng vào bất kỳ ngày nào khác.
Hãy chắc chắn rằng đường dẫn chính xác được bao gồm. PATH bên trong cron sẽ không (không có khả năng) giống với PATH của người dùng.
Lưu ý rằng có một tập lệnh cuối tháng được thử nghiệm (như được chỉ ra bên dưới) có thể gọi nhiều tiện ích hoặc tập lệnh khác.
Điều này cũng sẽ tránh được vấn đề bổ sung mà cron tạo ra với dòng lệnh đầy đủ:
- Cron chia dòng lệnh trên bất kỳ
%
ngay cả khi được trích dẫn bằng '
hoặc "
(chỉ một \
tác phẩm ở đây). Đó là một cách phổ biến trong đó công việc cron thất bại.
Bạn có thể kiểm tra xem end_of_month.sh
tập lệnh có hoạt động chính xác vào một ngày nào đó không (không phải đợi đến cuối tháng để phát hiện ra tập lệnh không hoạt động) bằng cách kiểm tra tập lệnh đó với faketime:
$ faketime 2018/10/31 ./end_of_month echo "Command will be executed...."
Command will be executed....