Saya membaca dari sebuah instruksi untuk menjadwalkan sebuah skrip pada hari terakhir bulan itu:
Catatan:
Pembaca yang cerdik mungkin bertanya-tanya bagaimana Anda dapat mengatur perintah untuk dieksekusi pada hari terakhir setiap bulan karena Anda tidak dapat menetapkan nilai dayofmonth untuk mencakup setiap bulan. Masalah ini telah menjangkiti programmer Linux dan Unix, dan telah melahirkan beberapa solusi yang berbeda. Metode yang umum adalah menambahkan pernyataan jika-maka yang menggunakan perintah tanggal untuk memeriksa apakah tanggal besok adalah 01:00 12 * * * if [`date +%d -d tomorrow` = 01 ] ; then ; command1
Ini memeriksa setiap hari pada jam 12 siang untuk melihat apakah itu adalah hari terakhir bulan itu, dan jika demikian, cron menjalankan perintah.
Bagaimana cara [`date +%d -d tomorrow` = 01 ]
kerjanya?
Apakah benar menyatakan then; command1
?
sumber
; endif
?[
dan tidak adafi
di akhir. Juga,%
khusus untuk crontab.Jawaban:
Abstrak
Kode yang benar adalah:
Panggil skrip ini
end_of_month.sh
dan panggilan dalam cron sederhana:Itu akan menjalankan skrip
end_of_month
(yang secara internal akan memeriksa bahwa hari itu adalah hari terakhir dalam sebulan) hanya pada hari ke 28, 29, 30 dan 31. Tidak perlu memeriksa akhir bulan pada hari lain.Posting lama.
Itu adalah kutipan dari buku "Linux Command Line dan Shell Scripting Bible" oleh Richard Blum, Christine Bresnahan hlm 442, Edisi Ketiga, John Wiley & Sons © 2015.
Ya, begitulah katanya, tapi itu salah / tidak lengkap:
fi
.[
dan berikut ini`
.`…`
."$(…)"
;
sesudahnyathen
Bagaimana aku tahu? (yah, berdasarkan pengalaman ☺) tetapi Anda dapat mencoba Shellcheck . Tempel kode dari buku (setelah tanda bintang) dan itu akan menunjukkan kepada Anda kesalahan yang tercantum di atas ditambah "hilang shebang". Script tanpa kesalahan di Shellcheck adalah ini:
#!/bin/sh if [ "$(date +%d -d tomorrow)" = 01 ] ; then script.sh; fi
Situs itu berfungsi karena apa yang ditulis adalah "kode shell". Itu adalah sintaks yang bekerja di banyak shell.
Beberapa masalah yang tidak disebutkan shellcheck adalah:
Diasumsikan bahwa perintah tanggal adalah versi tanggal GNU. Yang dengan
-d
opsi yang menerimatomorrow
sebagai nilai (busybox memiliki opsi -d tetapi tidak mengerti besok dan BSD memiliki-d
pilihan tetapi tidak terkait dengan "tampilan" waktu).Lebih baik mengatur format setelah semua opsi
date -d tomorrow +'%d'
.Waktu mulai cron selalu dalam waktu lokal, yang dapat membuat satu pekerjaan dimulai 1 jam lebih awal dari hari yang tepat dihitung jika DST (waktu musim panas) ditetapkan atau tidak disetel.
Apa yang kami lakukan adalah skrip shell yang bisa disebut dengan cron. Kami selanjutnya dapat memodifikasi skrip untuk menerima argumen dari program atau perintah untuk dieksekusi, seperti ini (akhirnya, kode yang benar):
Panggil skrip ini
end_of_month.sh
dan panggilan dalam cron sederhana:Itu akan menjalankan skrip
end_of_month
(yang secara internal akan memeriksa bahwa hari itu adalah hari terakhir dalam sebulan) hanya pada hari ke 28, 29, 30 dan 31. Tidak perlu memeriksa akhir bulan pada hari lain.Pastikan jalur yang benar disertakan. PATH di dalam cron tidak akan (tidak mungkin) sama dengan PATH pengguna.
Perhatikan bahwa ada satu skrip akhir bulan yang diuji (seperti ditunjukkan di bawah) yang dapat memanggil banyak utilitas atau skrip lain.
Ini juga akan menghindari masalah tambahan yang dihasilkan cron dengan baris perintah penuh:
%
bahkan jika dikutip dengan'
atau"
(hanya\
berfungsi di sini). Itu adalah cara umum di mana pekerjaan cron gagal.Anda dapat menguji apakah
end_of_month.sh
skrip bekerja dengan benar pada tanggal tertentu (tanpa menunggu hingga akhir bulan untuk menemukan itu tidak berfungsi) dengan mengujinya dengan faketime:sumber
date
(ataudate
bawaan dari ksh93 jika ksh93 dibangun sebagai bagian dari ast-open) mendukungdate -d tomorrow +%s
ataudate +%s tomorrow
).* * * * * echo "$(date -u +'date %c')" >>~/testfile
tidak akan berfungsi karena orang lupa mengutip\%
(yang menjadi sulit untuk di-debug jika hanya satu percobaan setiap bulan yang memungkinkan). @ KusalanandaDengan asumsi bahwa kesalahan sintaks sudah diperbaiki, dan perintah dirumuskan ulang sedikit menjadi kurang verbose:
Ini berjalan
date +%d -d tomorrow
(dengan asumsi bahwa itu GNUdate
yang digunakan) untuk mendapatkan tanggal besok sebagai angka dua digit. Jika angkanya tidak01
, maka hari ini bukan hari terakhir dalam sebulan. Dalam hal ini, tes berhasil dancommand1
yang tidak dieksekusi. Pekerjaan dijalankan pada siang hari pada hari-hari yang mungkin merupakan hari terakhir bulan itu.Perintah asli:
Ini memiliki beberapa masalah:
[
.;
langsung setelah ituthen
.%
khusus dalam spesifikasi pekerjaan cron dan harus diloloskan sebagai\%
(lihatman 5 crontab
).fi
di akhir yang cocok denganif
.sumber
[ ... ] && command1
alih-alihif...
adalah bahwa pada hari-hari yang bukan hari terakhir bulan itu, pekerjaan cron akan berakhir dengan status keluar yang tidak nol dan bahwa kegagalan mungkin harus dilaporkan. Menggunakan[ "$(...)" != 01 ] || command1
adalah cara lain untuk menghindari masalah.;
antarathen
dancommand1
."
atau'
(kecuali\
), tanda persen%
akan membuat cron memutus garis menjadi dua bagian. Itu adalah satu cara yang biasa untuk membuat cron gagal.Untuk menjadwalkan hari terakhir setiap bulan, Anda dapat mencoba:
0 0 15,L * *
.sumber