Periksa apakah skrip dimulai dengan cron, daripada dipanggil secara manual
23
Apakah ada variabel yang diset cron saat menjalankan program? Jika skrip dijalankan oleh cron, saya ingin melewati beberapa bagian; jika tidak panggil bagian-bagian itu.
Bagaimana saya bisa tahu jika skrip Bash dimulai oleh cron?
@terdon: mungkin karena psdidokumentasikan dengan sangat buruk (terutama versi Linux yang mendukung beberapa gaya sintaks yang berbeda) dan halaman manual bahkan lebih padat dan samar daripada kebanyakan alat. Saya curiga kebanyakan orang bahkan tidak menyadari betapa berguna dan serbagunanya sebuah alat ps.
cas
Jawaban:
31
Saya tidak mengetahui bahwa cronmelakukan apa saja pada lingkungannya secara default yang dapat digunakan di sini, tetapi ada beberapa hal yang dapat Anda lakukan untuk mendapatkan efek yang diinginkan.
1) Buat tautan keras atau lunak ke file skrip, sehingga, misalnya, myscriptdan myscript_via_cronarahkan ke file yang sama. Anda kemudian dapat menguji nilai $0di dalam skrip ketika Anda ingin menjalankan atau menghilangkan bagian-bagian tertentu dari kode. Masukkan nama yang sesuai di crontab Anda, dan Anda siap.
2) Tambahkan opsi ke skrip, dan atur opsi itu dalam permintaan crontab. Misalnya, tambahkan opsi -c, yang memberi tahu skrip untuk menjalankan atau menghilangkan bagian kode yang sesuai, dan menambahkan -cnama perintah di crontab Anda.
Dan tentu saja, cron dapat mengatur variabel lingkungan yang berubah-ubah, sehingga Anda bisa meletakkan baris seperti RUN_BY_CRON="TRUE"di crontab Anda, dan memeriksa nilainya di skrip Anda.
jawaban oleh cas bekerja sangat baik dan dapat digunakan untuk hal lain juga
Deian
19
Skrip yang dijalankan dari cron tidak dijalankan di shell interaktif. Skrip startup juga tidak. Perbedaannya adalah bahwa kerang interaktif memiliki STDIN dan STDOUT yang melekat pada tty.
Metode 1: periksa apakah $-menyertakan ibendera. idiatur untuk shell interaktif.
Metode 3: uji tty Anda. itu tidak seperti yang diandalkan, tapi untuk pekerjaan cron sederhana Anda harus ok, seperti cron tidak secara default mengalokasikan tty untuk script.
Perhatikan bahwa perintah $ PS1 tidak berfungsi ketika memeriksa apakah skrip dijalankan oleh systemd atau tidak. $ - satu tidak
mveroone
1
Tautan Universitas Winnipeg Anda rusak.
WinEunuuchs2Unix
1
@TimKennedy Terima kasih .... dari Edmonton :)
WinEunuuchs2Unix
'case "$ -" in' tampaknya tidak berfungsi dalam skrip bash.
Hobadee
@Hobadee - setiap bashsaya memiliki akses ke memiliki $ -, seperti halnya dashdan ksh. bahkan cangkang terbatas di Solaris memilikinya. Platform apa yang Anda coba gunakan di tempat yang tidak berfungsi? Apa yang case "$-" in *i*) echo true ;; *) echo false ;; esacditunjukkan kepada Anda?
Tim Kennedy
7
Pertama, dapatkan PID cron, lalu dapatkan PID (PPID) induk proses saat ini, dan bandingkan:
CRONPID=$(ps ho %p -C cron)
PPID=$(ps ho %P -p $$)if[ $CRONPID -eq $PPID ];then echo Cron is our parent.;fi
Jika skrip Anda dimulai oleh proses lain yang mungkin dimulai oleh cron, maka Anda dapat berjalan mundur dari PID induk hingga Anda mendapatkan $ CRONPID atau 1 (PID init).
sesuatu seperti ini, mungkin (Untested-But-It-Might-Work <TM>):
PPID=$$ # start from current PID
CRON_IS_PARENT=0
CRONPID=$(ps ho %p -C cron)while[ $CRON_IS_PARENT -ne 1]&&[ $PPID -ne 1];do
PPID=$(ps ho %P -p $PPID)[ $CRONPID -eq $PPID ]&& CRON_IS_PARENT=1done
Dari Deian: Ini adalah versi yang diuji pada RedHat Linux
# start from current PID
MYPID=$$
CRON_IS_PARENT=0# this might return a list of multiple PIDs
CRONPIDS=$(ps ho %p -C crond)
CPID=$MYPID
while[ $CRON_IS_PARENT -ne 1]&&[ $CPID -ne 1];do
CPID_STR=$(ps ho %P -p $CPID)# the ParentPID came up as a string with leading spaces# this will convert it to int
CPID=$(($CPID_STR))# now loop the CRON PIDs and compare them with the CPIDfor CRONPID in $CRONPIDS ;do[ $CRONPID -eq $CPID ]&& CRON_IS_PARENT=1# we could leave earlier but it's okay like that toodonedone# now do whatever you want with the informationif["$CRON_IS_PARENT"=="1"];then
CRON_CALL="Y"else
CRON_CALL="N"fi
echo "CRON Call: ${CRON_CALL}"
Pada Solaris cron memulai sebuah shell dan shell menjalankan skrip, yang dengan sendirinya memulai shell lain. Jadi pid orang tua dalam skrip bukanlah pid dari cron.
ceving
4
Jika file skrip Anda dipanggil oleh crondan berisi shell di baris pertama seperti #!/bin/bashAnda harus mencari nama induk-induk untuk tujuan Anda.
1) crondipanggil pada waktu yang ditentukan di Anda crontab, menjalankan shell 2) shell mengeksekusi skrip Anda 3) skrip Anda sedang berjalan
PID induk tersedia dalam bash sebagai variabel $PPID. The psperintah untuk mendapatkan PID induk dari induk PID adalah:
PPPID=`ps h -o ppid= $PPID`
tetapi kita membutuhkan nama perintah, bukan pid, jadi kita panggil
P_COMMAND=`ps h -o %c $PPPID`
sekarang kita hanya perlu menguji hasilnya untuk "cron"
Ini hanya berfungsi untuk Linux ps. Untuk MacOS (dan juga Linux, mungkin * BSD juga), Anda dapat menggunakan P_COMMAND berikut:P_COMMAND=$(basename -a $(ps h -o comm $PPPID))
mdd
1
Bekerja di FreeBSD atau di Linux:
if["Z$(ps o comm="" -p $(ps o ppid="" -p $$))"=="Zcron"-o \
"Z$(ps o comm="" -p $(ps o ppid="" -p $(ps o ppid="" -p $$)))"=="Zcron"]then
echo "Called from cron"else
echo "Not called from cron"fi
Anda dapat naik sejauh pohon proses yang Anda inginkan.
Sederhana echo $TERM | mail [email protected]di cron menunjukkan kepada saya bahwa pada Linux dan AIX, cron tampaknya diatur $TERMke 'bodoh'.
Sekarang secara teoritis mungkin masih ada terminal bisu yang sebenarnya di sekitar, tapi saya menduga bahwa untuk sebagian besar kesempatan, itu sudah cukup ...
Tidak ada jawaban otoritatif, tetapi variabel prompt ( $PS1) dan terminal ( $TERM) cukup baik di sini. Beberapa sistem mengatur TERM=dumbsementara sebagian besar membiarkannya kosong, jadi kami hanya akan memeriksa:
if["${TERM:-dumb}$PS1"!="dumb"];then
echo "This is not a cron job"fi
Kode di atas menggantikan kata "bodoh" ketika tidak ada nilai untuk $TERM. Oleh karena itu, kondisional akan menyala ketika tidak ada $TERMatau $TERMdiatur ke "bodoh" atau jika $PS1variabel tidak kosong.
Saya sudah menguji ini pada Debian 9 ( TERM=), CentOS 6.4 & 7.4 ( TERM=dumb), dan FreeBSD 7.3 ( TERM=).
ps
?ps
didokumentasikan dengan sangat buruk (terutama versi Linux yang mendukung beberapa gaya sintaks yang berbeda) dan halaman manual bahkan lebih padat dan samar daripada kebanyakan alat. Saya curiga kebanyakan orang bahkan tidak menyadari betapa berguna dan serbagunanya sebuah alatps
.Jawaban:
Saya tidak mengetahui bahwa
cron
melakukan apa saja pada lingkungannya secara default yang dapat digunakan di sini, tetapi ada beberapa hal yang dapat Anda lakukan untuk mendapatkan efek yang diinginkan.1) Buat tautan keras atau lunak ke file skrip, sehingga, misalnya,
myscript
danmyscript_via_cron
arahkan ke file yang sama. Anda kemudian dapat menguji nilai$0
di dalam skrip ketika Anda ingin menjalankan atau menghilangkan bagian-bagian tertentu dari kode. Masukkan nama yang sesuai di crontab Anda, dan Anda siap.2) Tambahkan opsi ke skrip, dan atur opsi itu dalam permintaan crontab. Misalnya, tambahkan opsi
-c
, yang memberi tahu skrip untuk menjalankan atau menghilangkan bagian kode yang sesuai, dan menambahkan-c
nama perintah di crontab Anda.Dan tentu saja, cron dapat mengatur variabel lingkungan yang berubah-ubah, sehingga Anda bisa meletakkan baris seperti
RUN_BY_CRON="TRUE"
di crontab Anda, dan memeriksa nilainya di skrip Anda.sumber
Skrip yang dijalankan dari cron tidak dijalankan di shell interaktif. Skrip startup juga tidak. Perbedaannya adalah bahwa kerang interaktif memiliki STDIN dan STDOUT yang melekat pada tty.
Metode 1: periksa apakah
$-
menyertakani
bendera.i
diatur untuk shell interaktif.Metode 2: cek
$PS1
kosongreferensi: http://techdoc.kvindesland.no/linux/gnubooks/bash/bashref_54.html
Metode 3: uji tty Anda. itu tidak seperti yang diandalkan, tapi untuk pekerjaan cron sederhana Anda harus ok, seperti cron tidak secara default mengalokasikan tty untuk script.
Ingatlah bahwa Anda dapat memaksa shell interaktif menggunakan
-i
, tetapi Anda mungkin akan sadar jika Anda melakukan ini ...sumber
bash
saya memiliki akses ke memiliki $ -, seperti halnyadash
danksh
. bahkan cangkang terbatas di Solaris memilikinya. Platform apa yang Anda coba gunakan di tempat yang tidak berfungsi? Apa yangcase "$-" in *i*) echo true ;; *) echo false ;; esac
ditunjukkan kepada Anda?Pertama, dapatkan PID cron, lalu dapatkan PID (PPID) induk proses saat ini, dan bandingkan:
Jika skrip Anda dimulai oleh proses lain yang mungkin dimulai oleh cron, maka Anda dapat berjalan mundur dari PID induk hingga Anda mendapatkan $ CRONPID atau 1 (PID init).
sesuatu seperti ini, mungkin (Untested-But-It-Might-Work <TM>):
Dari Deian: Ini adalah versi yang diuji pada RedHat Linux
sumber
Jika file skrip Anda dipanggil oleh
cron
dan berisi shell di baris pertama seperti#!/bin/bash
Anda harus mencari nama induk-induk untuk tujuan Anda.1)
cron
dipanggil pada waktu yang ditentukan di Andacrontab
, menjalankan shell 2) shell mengeksekusi skrip Anda 3) skrip Anda sedang berjalanPID induk tersedia dalam bash sebagai variabel
$PPID
. Theps
perintah untuk mendapatkan PID induk dari induk PID adalah:tetapi kita membutuhkan nama perintah, bukan pid, jadi kita panggil
sekarang kita hanya perlu menguji hasilnya untuk "cron"
Sekarang Anda dapat menguji di mana saja dalam skrip Anda
Semoga berhasil!
sumber
P_COMMAND=$(basename -a $(ps h -o comm $PPPID))
Bekerja di FreeBSD atau di Linux:
Anda dapat naik sejauh pohon proses yang Anda inginkan.
sumber
Solusi umum untuk pertanyaan "adalah keluaran saya terminal atau saya menjalankan skrip" adalah:
sumber
Sederhana
echo $TERM | mail [email protected]
di cron menunjukkan kepada saya bahwa pada Linux dan AIX, cron tampaknya diatur$TERM
ke 'bodoh'.Sekarang secara teoritis mungkin masih ada terminal bisu yang sebenarnya di sekitar, tapi saya menduga bahwa untuk sebagian besar kesempatan, itu sudah cukup ...
sumber
Tidak ada jawaban otoritatif, tetapi variabel prompt (
$PS1
) dan terminal ($TERM
) cukup baik di sini. Beberapa sistem mengaturTERM=dumb
sementara sebagian besar membiarkannya kosong, jadi kami hanya akan memeriksa:Kode di atas menggantikan kata "bodoh" ketika tidak ada nilai untuk
$TERM
. Oleh karena itu, kondisional akan menyala ketika tidak ada$TERM
atau$TERM
diatur ke "bodoh" atau jika$PS1
variabel tidak kosong.Saya sudah menguji ini pada Debian 9 (
TERM=
), CentOS 6.4 & 7.4 (TERM=dumb
), dan FreeBSD 7.3 (TERM=
).sumber