Di mana saya dapat mengatur variabel lingkungan yang akan digunakan crontab?

266

Saya memiliki crontab yang berjalan setiap jam. Pengguna yang menjalankannya memiliki variabless lingkungan dalam .bash_profilepekerjaan itu ketika pengguna menjalankan pekerjaan dari terminal, namun, jelas ini tidak diambil oleh crontab saat dijalankan.

Saya sudah mencoba mengaturnya .profiledan .bashrctetapi mereka masih belum dijemput. Adakah yang tahu di mana saya bisa meletakkan vars lingkungan yang dapat diambil oleh crontab?

James
sumber

Jawaban:

88

Mintalah 'cron' menjalankan skrip shell yang mengatur lingkungan sebelum menjalankan perintah.

Selalu.

#   @(#)$Id: crontab,v 4.2 2007/09/17 02:41:00 jleffler Exp $
#   Crontab file for Home Directory for Jonathan Leffler (JL)
#-----------------------------------------------------------------------------
#Min     Hour    Day     Month   Weekday Command
#-----------------------------------------------------------------------------
0        *       *       *       *       /usr/bin/ksh /work1/jleffler/bin/Cron/hourly
1        1       *       *       *       /usr/bin/ksh /work1/jleffler/bin/Cron/daily
23       1       *       *       1-5     /usr/bin/ksh /work1/jleffler/bin/Cron/weekday
2        3       *       *       0       /usr/bin/ksh /work1/jleffler/bin/Cron/weekly
21       3       1       *       *       /usr/bin/ksh /work1/jleffler/bin/Cron/monthly

Skrip di ~ / bin / Cron adalah semua tautan ke satu skrip, 'runcron', yang terlihat seperti:

:       "$Id: runcron.sh,v 2.1 2001/02/27 00:53:22 jleffler Exp $"
#
#       Commands to be performed by Cron (no debugging options)

#       Set environment -- not done by cron (usually switches HOME)
. $HOME/.cronfile

base=`basename $0`
cmd=${REAL_HOME:-/real/home}/bin/$base

if [ ! -x $cmd ]
then cmd=${HOME}/bin/$base
fi

exec $cmd ${@:+"$@"}

(Ditulis menggunakan standar pengkodean yang lebih lama - saat ini, saya akan menggunakan shebang '#!' Di awal.)

'~ / .Cronfile' adalah variasi pada profil saya untuk digunakan oleh cron - sangat non-interaktif dan tidak ada gaung demi menjadi berisik. Anda dapat mengatur untuk mengeksekusi. Profil dan sebagainya sebagai gantinya. (Barang-barang REAL_HOME adalah artefak dari lingkungan saya - Anda dapat berpura-pura sama dengan $ HOME.)

Jadi, kode ini membaca lingkungan yang sesuai dan kemudian menjalankan versi non-Cron dari perintah dari direktori home saya. Jadi, misalnya, perintah 'hari kerja' saya terlihat seperti:

:       "@(#)$Id: weekday.sh,v 1.10 2007/09/17 02:42:03 jleffler Exp $"
#
#       Commands to be done each weekday

# Update ICSCOPE
n.updics

Perintah 'harian' lebih sederhana:

:       "@(#)$Id: daily.sh,v 1.5 1997/06/02 22:04:21 johnl Exp $"
#
#       Commands to be done daily

# Nothing -- most things are done on weekdays only

exit 0
Jonathan Leffler
sumber
246

Anda dapat mendefinisikan variabel lingkungan di crontab itu sendiri ketika menjalankan crontab -edari baris perintah.

LANG=nb_NO.UTF-8
LC_ALL=nb_NO.UTF-8
# m h  dom mon dow   command

* * * * * sleep 5s && echo "yo"

Fitur ini hanya tersedia untuk implementasi cron tertentu. Ubuntu dan Debian saat ini menggunakan vixie-cron yang memungkinkan ini untuk dideklarasikan dalam file crontab (juga GNU mcron ).

Archlinux dan RedHat menggunakan cronie yang tidak memungkinkan variabel lingkungan untuk dideklarasikan dan akan membuang kesalahan sintaks di cron.log. Penanganan masalah dapat dilakukan per masuk:

# m h  dom mon dow   command
* * * * * export LC_ALL=nb_NO.UTF-8; sleep 5s && echo "yo"
carestad
sumber
58
Perhatikan bahwa Anda tidak dapat menggunakan substitusi variabel seperti dalam shell, jadi deklarasi seperti PATH = / usr / local / bin: $ PATH diartikan secara harfiah.
Zac
8
Saya dapat mengatur variabel lingkungan di crontab itu sendiri di bawah RedHat 4.4.7-3 dan cronie-1.4.4-15.el6.x86_64
Bruno Lange
7
Anda tidak benar-benar perlu mengekspor variabel jika variabel hanya digunakan dalam perintah, cukup tambahkan dulu sebelum perintah Anda. "* * * * * sleep 5s; LC_ALL = nb_NO.UTF-8 echo $ LC_ALL"
vutran
@ BrunoLange, bisakah Anda membagikan berbagi bagaimana Anda mengaturnya?
Newskooler
145

Saya punya satu solusi lagi untuk masalah ini:

0 5 * * * . $HOME/.profile; /path/to/command/to/run

Dalam hal ini ia akan memilih semua variabel lingkungan yang ditentukan dalam $HOME/.profilefile Anda .

Tentu saja $HOMEjuga tidak diatur, Anda harus menggantinya dengan path lengkap Anda $HOME.

Vishal
sumber
Ini bekerja untuk saya setelah banyak berjuang untuk menemukan jawabannya, terima kasih!
vladimir montealegre
5
ini tidak bekerja untuk saya sampai saya menyadari saya telah meninggalkan periode sebelum $ HOME. Apa tepatnya yang dilakukan periode itu?
flymike
9
Periode ini setara dengan perintah "sumber": tldp.org/LDP/abs/html/special-chars.html#DOTREF
Jeff W
@ PeterLee apakah sesuatu yang disebutkan berhasil untuk Anda? Saya menulis ini karena solusi yang disebutkan di atas tidak efektif bagi saya. Jika solusi yang disebutkan di atas tidak berfungsi, saya harus melakukan riset untuk menemukan alasannya. ;-)
Vishal
3
@Vishal Sebenarnya, sekarang bekerja untuk saya. Saya mencoba source ~/.bashrc, dan ternyata .bashrcfile saya agak bertentangan dengan pekerjaan cron. Jika saya menggunakan .env_setup_rcfile yang sangat sederhana dengan hanya satu baris export MY_ENV_VAR=my_env_val:, sebenarnya berfungsi. Lihat posting saya: stackoverflow.com/questions/15557777/…
Peter Lee
63

Mengatur vars in /etc/environmentjuga bekerja untuk saya di Ubuntu. Pada 12,04, variabel dalam /etc/environmentdimuat untuk cron.

Augusto Destrero
sumber
11
Jawaban terbaik, jalankan saja env >> /etc/environmentdan semua env vars saat ini sekarang tersedia di pekerjaan CRON.
Savageman
6
ini sangat bagus untuk saya. terutama karena saya menjalankan Docker Container, jadi saya tidak terlalu peduli tentang implikasi "sistem luas".
Lucas Pottersky
14
@Savageman itu seperti membunuh lalat dengan bom fusi, juga taruhannya perilaku tak terduga sangat tinggi.
Fran Marzoa
2
HATI-HATI: env >> /etc/environmentakan GAGAL jika ada tanda pagar di salah satu variabel lingkungan. Saya mengalami kesulitan saat memecahkan masalah aplikasi saya. Ternyata itu adalah kata sandi yang berisi '#' yang terpotong pada langkah itu.
asac
3
Ini harus menjadi jawaban yang dipilih. Saya tidak tahu mengapa orang mempersulit hal-hal dengan jawaban lain atau dengan hal-hal ini tentang env >> / etc / environment. Hanya berkedip edit / lingkungan dengan baik jika Anda ingin env vars ini tersedia secara universal: percobaan saya tampaknya mengkonfirmasi bahwa pernyataan ekspor untuk env vars di / etc / environment tersedia untuk crontab dan juga untuk pengguna. MASALAHNYA: sekali lagi dari eksperimen saya: tampaknya env vars ini TIDAK DIPERLUAS dalam crontab itu sendiri! ... yaitu mereka diperluas hanya dalam skrip yang disebut!
mike rodent
39

Jika Anda memulai skrip yang Anda jalankan melalui cron dengan:

#!/bin/bash -l

Mereka harus mengambil ~/.bash_profilevariabel lingkungan Anda

breizhmg
sumber
4
Jawaban ini harus mendapatkan lebih banyak upvotes dan hanya menjadi jawaban yang dipilih: Sangat sederhana dan elegan dan menghindari kludges yang tak terhitung jumlahnya yang akan membutuhkan melompat di seluruh sistem.
JakeGould
Saya suka jawaban ini +1. Bisakah / Haruskah ini digunakan saat menjalankan rootcrontab? Tidak ada /home/rootfolder di sistem saya dan jadi saya tidak melihat bagaimana ini akan bekerja dengan rootcrontab. Ide ide?
Seamus
Dalam naskah itu sendiri. Yang kemudian Anda jalankan dengan cron secara normal.
breizhmg
@ Jim lihat contoh ini , gunakan file executable klasik (chmod 777) #!/bin/bash. Keajaiban di sini adalah untuk menambahkan-l
Peter Krauss
22

Memperluas contoh @carestad, yang menurut saya lebih mudah, adalah menjalankan skrip dengan cron dan memiliki lingkungan dalam skrip.

Dalam file crontab -e:

SHELL=/bin/bash

*/1 * * * * $HOME/cron_job.sh

Dalam file cron_job.sh:

#!/bin/bash
source $HOME/.bash_profile
some_other_cmd

Perintah apa pun setelah sumber .bash_profile akan memiliki lingkungan Anda seolah-olah Anda masuk.

Robert Brisita
sumber
16

Bagi saya, saya harus mengatur variabel lingkungan untuk aplikasi php. Saya membuatnya kembali dengan menambahkan kode berikut ke crontab saya.

$ sudo  crontab -e

crontab:

ENVIRONMENT_VAR=production

* * * * * /home/deploy/my_app/cron/cron.doSomethingWonderful.php

dan di dalam doSomethingWonderful.php saya bisa mendapatkan nilai lingkungan dengan:

<?php     
echo $_SERVER['ENVIRONMENT_VAR']; # => "production"

Saya harap ini membantu!

karlingen
sumber
Ini tidak berhasil untuk saya. Variabel lingkungan tidak tersedia dalam skrip yang dipanggil di dalam crontab.
Nikhil
12

Apa pun yang Anda atur crontabakan tersedia di cronjobs, baik secara langsung dan menggunakan variabel dalam skrip.

Gunakan mereka dalam definisi cronjob

Anda dapat mengkonfigurasi crontabsehingga menetapkan variabel yang kemudian dapat digunakan cronjob:

$ crontab -l
myvar="hi man"
* * * * * echo "$myvar. date is $(date)" >> /tmp/hello

Sekarang file tersebut /tmp/hellomenunjukkan hal-hal seperti:

$ cat /tmp/hello 
hi man. date is Thu May 12 12:10:01 CEST 2016
hi man. date is Thu May 12 12:11:01 CEST 2016

Gunakan mereka dalam skrip yang dijalankan oleh cronjob

Anda dapat mengonfigurasi crontabsehingga menetapkan variabel yang kemudian dapat digunakan skrip:

$ crontab -l
myvar="hi man"
* * * * * /bin/bash /tmp/myscript.sh

Dan katakan skripnya /tmp/myscript.shseperti ini:

echo "Now is $(date). myvar=$myvar" >> /tmp/myoutput.res

Ini menghasilkan file yang /tmp/myoutput.resmenunjukkan:

$ cat /tmp/myoutput.res
Now is Thu May 12 12:07:01 CEST 2016. myvar=hi man
Now is Thu May 12 12:08:01 CEST 2016. myvar=hi man
...
fedorqui 'SO berhenti merugikan'
sumber
7

Memperluas pada @Robert Brisita baru saja berkembang, juga jika Anda tidak ingin mengatur semua variabel profil dalam skrip, Anda dapat memilih variabel untuk diekspor di bagian atas skrip

Dalam file crontab -e:

SHELL=/bin/bash

*/1 * * * * /Path/to/script/script.sh

Di script.sh

#!/bin/bash
export JAVA_HOME=/path/to/jdk

some-other-command
Marcos Pousada
sumber
7

Dari pada

0  *  *  *  *  sh /my/script.sh

Gunakan bash -l -c

0  *  *  *  *  bash -l -c 'sh /my/script.sh'
Ilya Kharlamov
sumber
1
Mengapa ini bukan hanya memiliki deklarasi Bash di bagian atas file -lseperti ini #!/bin/bash -l:? Jawaban lain ini sederhana dan elegan.
JakeGould
1
Bagaimana jika saya perlu menjalankan skrip perl / python / ruby ​​bukan bash? Saya tidak bisa menambahkan #! / Bin / bash -l ke bagian atas skrip python.
Ilya Kharlamov
"Bagaimana jika saya perlu menjalankan skrip perl / python / ruby ​​bukan bash?" Cukup adil. Tetapi dalam pikiran saya Anda dapat menulis bungkus skrip Bash sederhana yang kemudian memanggil skrip Python. Saya melakukan hal serupa untuk skrip PHP. Alasannya adalah proses penguncian jauh lebih baik dan dapat diandalkan di Bash, tetapi skrip Bash masih sakit kepala. Jadi saya menulis hal-hal dalam PHP untuk hal-hal yang kompleks dan membiarkan Bash menangani sisanya.
JakeGould
3

Saya menggunakan Oh-my-zshdi macbook saya, jadi saya sudah mencoba banyak hal untuk menjalankan tugas crontab, tetapi akhirnya, solusi saya adalah mendahulukan .zshrcsebelum perintah dijalankan.

*/30 * * * * . $HOME/.zshrc; node /path/for/my_script.js

Tugas ini berjalan setiap 30 menit dan menggunakan .zshrcprofil untuk menjalankan perintah simpul saya.

Jangan lupa untuk menggunakan titik sebelum $HOMEvar.

Stiakov
sumber
2

Cara lain - terinspirasi oleh jawaban ini - untuk "menyuntikkan" variabel adalah sebagai berikut (contoh fcron):

%daily 00 12 \
    set -a; \
    . /path/to/file/containing/vars; \
    set +a; \
    /path/to/script/using/vars

Dari help set:

-a Tandai variabel yang dimodifikasi atau dibuat untuk ekspor.

Menggunakan + daripada - menyebabkan bendera ini dimatikan.

Jadi segala sesuatu di antaranya set -dan set +diekspor ke envdan kemudian tersedia untuk skrip lain, dll. Tanpa menggunakan setvariabel bersumber tetapi tinggal sethanya di .

Selain itu, sangat berguna untuk meneruskan variabel ketika suatu program membutuhkan akun non-root untuk dijalankan tetapi Anda memerlukan beberapa variabel di dalam lingkungan pengguna lain itu. Di bawah ini adalah contoh yang lewat di nullmailer vars untuk memformat header email:

su -s /bin/bash -c "set -a; \
                    . /path/to/nullmailer-vars; \
                    set +a; \
                    /usr/sbin/logcheck" logcheck
Saucier
sumber
2

Saya mencoba sebagian besar solusi yang disediakan, tetapi tidak ada yang berhasil pada awalnya. Tapi ternyata bukan solusi yang gagal. Rupanya, ~/.bashrcfile saya dimulai dengan blok kode berikut:

case $- in
    *i*) ;;
    *) return;;
esac

Ini pada dasarnya adalah case statementyang memeriksa set opsi saat ini di shell saat ini untuk menentukan bahwa shell sedang berjalan secara interaktif. Jika shell dijalankan secara interaktif, maka shell akan beralih ke sumber ~/.bashrcfile. Namun, dalam shell yang dipanggil oleh cron, $-variabel tidak mengandung inilai yang menunjukkan interaktivitas. Oleh karena itu, ~/.bashrcfile tidak pernah didapatkan sepenuhnya. Akibatnya, variabel lingkungan tidak pernah ditetapkan. Jika ini adalah masalah Anda, jangan ragu untuk mengomentari blok kode sebagai berikut dan coba lagi:

# case $- in
#     *i*) ;;
#     *) return;;
# esac

Saya harap ini ternyata bermanfaat

Abdou
sumber
0

Anda juga dapat menambahkan perintah Anda dengan envmenyuntikkan variabel Lingkungan seperti:

0 * * * *   env VARIABLE=VALUE /usr/bin/mycommand
Hussam
sumber