cron mengabaikan variabel yang didefinisikan dalam ".bashrc" dan ".bash_profile"

49

Saya telah mendefinisikan variabel "SHELL" di file / etc / crontab:

[martin@martin ~]$ grep SHELL /etc/crontab 
SHELL=/usr/local/bin/bash
[martin@martin ~]$ file /usr/local/bin/bash
/usr/local/bin/bash: ELF 32-bit LSB executable, Intel 80386, version 1 (FreeBSD), dynamically linked (uses shared libs), for FreeBSD 8.0 (800107), stripped
[martin@martin ~]$ 

Selain itu, semua skrip saya di file / etc / crontab dimulai di bawah "martin" pengguna. Namun /home/martin/.bash_profile (untuk shell login) dan /home/martin/.bashrc (untuk shell non-logging) berisi beberapa variabel yang diabaikan dalam hal pekerjaan cron, tetapi digunakan jika saya login ke mesin lebih SSH atau buka sesi bash baru. Mengapa cron mengabaikan variabel-variabel itu? Bukankah cron hanya menjalankan "/ usr / local / bin / bash my-script.sh" dengan izin untuk pengguna "martin"?

Martin
sumber
2
Pengguna Ubuntu mungkin ingin mencatat bahwa default Ubuntu .bashrcmemiliki garis yang menghentikannya berjalan di shell non-interaktif.
joeytwiddle

Jawaban:

72

Anda dapat sumber file yang Anda inginkan di bagian atas skrip atau awal pekerjaan untuk pengguna yang menjalankan pekerjaan. Perintah "sumber" adalah built-in. Anda akan melakukan hal yang sama jika Anda mengedit file-file itu untuk memuat perubahan.

* * * * * source /home/user/.bash_profile; <command>

atau

#!/bin/bash
source /home/user/.bash_profile

<commands>
gNU.be
sumber
2
Perhatikan bahwa "sumber" mungkin tidak berfungsi jika cron tidak menggunakan bashshell. Saya telah menambahkan jawaban yang dapat menangani kasus ini ketika shellnya sh.
Jonathan
23

Karena itu bukan shell interaktif. Hal yang sama terjadi ketika Anda membuka beberapa terminal.

Lihat pertanyaan ini: Apa itu file .bashrc? | Pengguna Super

Dan juga yang ini:

Apa perbedaan antara .bashrc, .bash_profile, dan .environment? | Stack Overflow

Skrip yang berbeda menyala tergantung pada apakah koneksi adalah shell login (atau tidak), shell interaktif (atau tidak), atau keduanya.

Jika Anda ingin membuat bashrc Anda harus melakukan perubahan ini:

Ketika Bash dimulai secara non-interaktif, untuk menjalankan skrip shell, misalnya, ia mencari variabel BASH_ENV di lingkungan, memperluas nilainya jika muncul di sana, dan menggunakan nilai yang diperluas sebagai nama file untuk membaca dan mengeksekusi . Bash berperilaku seolah-olah perintah berikut dijalankan:

if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi 

tetapi nilai variabel PATH tidak digunakan untuk mencari nama file.

Seperti disebutkan di atas, jika shell non-interaktif dipanggil dengan --loginopsi, Bash mencoba membaca dan mengeksekusi perintah dari file startup shell login.

Sumber: Bash Startup Files | Manual Referensi Bash | gnu.org

Dave C
sumber
Jadi, jika kita mengatur BASH_ENV di dalam Cron, skrip cash bash akan menyatakan bahwa karena cron non-interaktif dan non-login.
CMCDragonkai
12

Anda mungkin tidak dapat menjalankan sourcejika shshell sedang digunakan. Ini dapat diubah dengan menambahkan baris berikut di crontab Anda:

SHELL=/bin/bash
* * * * * source "/root/.bashrc"; <command>

Anda juga dapat menentukan lingkungan:

BASH_ENV="/root/.bashrc"
* * * * * <command>

atau Anda dapat menggunakan lokal Anda /home/user/.bashrcjika itu adalah pekerjaan cron pengguna (misalnya crontab -e).

Catatan yang .bash_profilebisa diganti .bashrc, jika ada.

Kredit: Bagaimana cara mengganti cron shell (sh to bash)?

Jonathan
sumber
ini bekerja dengan baik juga untuk pekerjaan Acquia Cloud Scheduled, yang pada dasarnya adalah pekerjaan cron. Anda dapat melakukan hal yang sama, seperti:SHELL=/bin/bash && source /home/YOUR_USER_NAME/.bash_profile && sh ....
Alejandro Moreno
1

Hal lain yang dapat mengganggu sumber Anda .bashrcdari cronjob adalah pemeriksaan apa pun yang dilakukan file ini untuk mendeteksi kerang interaktif.

Misalnya, pada Ubuntu 18.04, default .bashrcuntuk pengguna dimulai dengan ini:

# ~/.bashrc: executed by bash(1) for non-login shells.
# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
# for examples

# If not running interactively, don't do anything
case $- in
    *i*) ;;
      *) return;;
esac

dan sumber itu tidak akan melakukan apa pun yang berguna karena akan segera keluar.

Francois Marier
sumber
1

Anda dapat meminta bash dengan -lopsi, seperti ini:

* * * * * /bin/bash -l /path/to/script arg1 arg2

The -lpilihan membuat bash masuk shell. Jadi, itu akan membaca pengguna .bash_profile. Itu tidak akan membaca pengguna .bashrckecuali secara eksplisit bersumber dari .bash_profile. Ini karena kerang non-interaktif tidak otomatis dibaca .bashrc. Tetapi Anda tidak perlu .bashrcuntuk pekerjaan cron karena .bashrcuntuk mengatur hal-hal yang berguna untuk shell interaktif .

Variasi:

Jika bash ada di PATH, tidak perlu menentukan jalur absolut:

* * * * * bash -l /path/to/script arg1 arg2

Pengoptimalan akan menggantikan shell saat ini dengan menggunakan exec:

* * * * * exec bash -l /path/to/script arg1 arg2
Robin A. Meade
sumber
1

bashbertindak berbeda apakah itu shell atau bahasa pemrograman normal (suka perlatau python).

Secara desain, pengaturan dalam ~/.bash_profile,, ~/.bashrcdll. Adalah bagi pengguna untuk mengatur hal-hal ketika bashmemainkan peran shell (shell login, shell interractive). Pikirkan tentang lingkungan yang Anda miliki di xterm(shell interaktif) atau di sshsesi (shell login) atau di konsol (shell login).

Di sisi lain, bashjuga merupakan bahasa pemrograman yang kuat - pikirkan banyak skrip untuk mengelola layanan di systemd- yang membutuhkan gaya kerja yang berbeda. Misalnya, ketika pengembang menulis skrip sistem atau bashprogram, ia tidak akan suka untuk sumber pengguna ~/.bash_profilesecara otomatis. Ini adalah program normal, bukan shell. Program normal (termasuk bashprogram) secara alami akan mewarisi pengaturan dari lingkungan kerja saat ini (shell), tetapi tidak mengaturnya .

Jika kita menulis sebuah program untuk cronin bash– itu kebetulan ditulis dalam bash; pada kenyataannya, kita dapat menulis dalam pythonatau perlatau progamming lainnya pada bahasa maka kita dapat memiliki pilihan untuk sumber bash's ~/.bash_profile(baca: pengaturan dari shell pengguna, yang kebetulan menjadi bahasa yang sama bahasa pemrograman Anda):

[ -f /home/user/.bash_profile ] && . /home/user/.bash_profile

Namun, bagaimana jika pengguna tertentu itu tidak menggunakan bashshellnya? Dia / dia dapat menggunakan zsh, ksh, fish, dll Jadi, praktek yang akan benar-benar bekerja ketika menulis program untuk kepentingan umum.

Jadi, Anda dapat sumber ~/.bash_profilejika Anda pikir itu akan berhasil. Tapi, di sini, ini bukan tentang apakah kita dapat sumber file, ini tentang bagaimana hal-hal seharusnya bekerja dalam sistem: konsep desain . Singkatnya: kita harus melihat bashsesuatu yang memiliki 2 peran: bahasa shell dan progamming . Maka semuanya akan jauh lebih mudah dipahami.

Bach Lien
sumber
0

Saya memiliki masalah yang sama ketika menjalankan aplikasi node dari cron yang menggunakan NVM, Untuk membuat bash shell untuk membaca file .bashrc dari cron hanya memerlukan perintah bash dengan opsi shell interaktif `-l.

misalnya: * * * * * /bin/bash -lc '/home/user/myapp.sh restart'

Jika itu tidak berhasil, coba setel variabel path di crontab

41 7 * * * /bin/bash -lc "PATH=$PATH:/home/user/.nvm/versions/node/v8.10.0/bin && /home/user/script.sh restart "
Shyam Jos
sumber
-1

Cara saya menghadapinya adalah ini:

1) Meletakkan variabel saya di (akhir) ~/.profile:

myVarInDotProfile="someValue"

2) Membuat skrip Bash untuk tugas cron (harian) ~/cronDaily.shsaya ( ) yang berisi perintah saya ditambah sumber berulang ~/.profle:

source ~/.profile
command ${myVarInDotProfile}/

3) menjadwalkan eksekusi skrip saya dari crontab, untuk berjalan setiap hari:

0 0 * * * bash ~/cronDaily.sh

Variabel saya tidak diabaikan dan perintah berjalan dengan sukses.


Beberapa orang mungkin mengatakan bahwa sumber intens seperti ~/.profileitu bermasalah. Dalam kasus khusus saya, saya tidak melihat mengapa ini merupakan masalah tetapi saya akan menyarankan untuk mempertimbangkan membuat file khusus untuk itu.

Secara umum, mungkin ada cara yang lebih baik untuk ini, tetapi itulah yang berhasil bagi saya setelah banyak kesakitan dan itu menjelaskan prinsip bahwa pada Bash 4.3.46, Anda tidak dapat sumber file dari crontab.

Arcticooling
sumber