Tôi có thể đặt các biến môi trường mà crontab sẽ sử dụng ở đâu?


266

Tôi có một crontab chạy mỗi giờ. Người dùng đang chạy nó có sự biến đổi môi trường trong .bash_profilecông việc khi người dùng chạy công việc từ thiết bị đầu cuối, tuy nhiên, rõ ràng những điều này không được crontab chọn khi nó chạy.

Tôi đã cố gắng thiết lập chúng trong .profile.bashrcnhưng họ vẫn dường như không để nhặt. Có ai biết nơi tôi có thể đặt lọ môi trường mà crontab có thể nhặt được không?

Câu trả lời:


88

Có 'cron' chạy tập lệnh shell đặt môi trường trước khi chạy lệnh.

Luôn luôn.

#   @(#)$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

Các tập lệnh trong ~ / bin / Cron đều là các liên kết đến một tập lệnh duy nhất, 'runcron', trông giống như:

:       "$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 ${@:+"$@"}

(Được viết bằng một tiêu chuẩn mã hóa cũ hơn - ngày nay, tôi sẽ sử dụng một shebang '#!' Khi bắt đầu.)

'~ / .Cronfile' là một biến thể trong hồ sơ của tôi để sử dụng bởi cron - hoàn toàn không tương tác và không gây tiếng vang vì lý do ồn ào. Bạn có thể sắp xếp để thực thi .profile và cứ thế. (Nội dung REAL_HOME là một vật phẩm trong môi trường của tôi - bạn có thể giả vờ nó giống như $ HOME.)

Vì vậy, mã này đọc môi trường thích hợp và sau đó thực thi phiên bản lệnh không Cron từ thư mục chính của tôi. Vì vậy, ví dụ, lệnh 'ngày trong tuần' của tôi trông như sau:

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

# Update ICSCOPE
n.updics

Lệnh 'hàng ngày' đơn giản hơn:

:       "@(#)$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

246

Bạn có thể xác định các biến môi trường trong chính crontab khi chạy crontab -etừ dòng lệnh.

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

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

Tính năng này chỉ có sẵn cho một số triển khai nhất định của cron. Ubuntu và Debian hiện đang sử dụng vixie-cron , cho phép những thứ này được khai báo trong tệp crontab (cũng là GNU mcron ).

ArchlinuxRedHat sử dụng croniekhông cho phép các biến môi trường được công bố và sẽ ném lỗi cú pháp trong cron.log. Giải pháp có thể được thực hiện mỗi lần nhập:

# m h  dom mon dow   command
* * * * * export LC_ALL=nb_NO.UTF-8; sleep 5s && echo "yo"

58
Lưu ý rằng bạn không thể sử dụng thay thế biến như trong shell, vì vậy một khai báo như PATH = / usr / local / bin: $ PATH được hiểu theo nghĩa đen.
Zac

8
Tôi đã có thể đặt các biến môi trường trong chính crontab theo RedHat 4.4.7-3 và cronie-1.4.4-15.el6.x86_64
Bruno Lange

7
Bạn không thực sự cần xuất các biến nếu các biến chỉ được sử dụng trong lệnh, chỉ cần thêm chúng trước lệnh của bạn. "* * * * * ngủ 5s; LC_ALL = nb_NO.UTF-8 echo $ LC_ALL"
vutran


@BrunoLange bạn có thể chia sẻ pelase như thế nào bạn đã quản lý để thiết lập chúng?
Newskooler

145

Tôi có thêm một giải pháp cho vấn đề này:

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

Trong trường hợp này, nó sẽ chọn tất cả các biến môi trường được xác định trong $HOME/.profiletệp của bạn .

Tất nhiên $HOMEcũng không được thiết lập, bạn phải thay thế nó bằng đường dẫn đầy đủ của bạn $HOME.


Điều này làm việc cho tôi sau khi đấu tranh rất nhiều để tìm câu trả lời, cảm ơn!
vladimir montealegre

5
việc này không hiệu quả với tôi cho đến khi tôi nhận ra mình đã bỏ qua khoảng thời gian trước $ HOME. Chính xác thì thời kỳ đó làm gì?
flymike

9
Khoảng thời gian này tương đương với lệnh "nguồn": tldp.org/LDP/abs/html/special-chars.html#DOTREF
Jeff W

@PeterLee có đề cập gì cho bạn không? Tôi đã viết điều này như các giải pháp được đề cập ở trên không hiệu quả đối với tôi. Nếu giải pháp được đề cập ở trên không hoạt động, tôi sẽ phải thực hiện một số nghiên cứu để tìm ra lý do. ;-)
Vishal 22/03/13

3
@Vishal Thật ra, bây giờ nó hoạt động với tôi. Tôi đã cố gắng source ~/.bashrcvà hóa ra .bashrctập tin của tôi có mâu thuẫn với công việc định kỳ. Nếu tôi sử dụng một .env_setup_rctệp rất đơn giản chỉ có một dòng: export MY_ENV_VAR=my_env_valnó thực sự hoạt động. Xem bài đăng của tôi: stackoverflow.com/questions/15557777/ Kẻ
Peter Lee

63

Cài đặt vars /etc/environmentcũng hoạt động với tôi trong Ubuntu. Kể từ ngày 12.04, các biến trong /etc/environmentđược tải cho cron.


11
Câu trả lời tốt nhất, chỉ cần thực hiện env >> /etc/environmentvà tất cả các lọ env hiện tại đã có sẵn trong các công việc CRON.
Savageman

6
điều này làm việc rất tốt cho tôi đặc biệt là vì tôi đang chạy vào Docker Container, vì vậy tôi không quan tâm nhiều đến ý nghĩa "toàn hệ thống".
Lucas Pottersky

14
@Savageman giống như giết ruồi bằng bom nhiệt hạch, cũng là cổ phần của hành vi bất ngờ cực kỳ cao.
Fran Marzoa

2
HÃY CẨN THẬN: env >> /etc/environmentsẽ FAIL nếu có dấu băm trong một trong các biến môi trường. Tôi đã có thời gian khó khăn nhất để khắc phục sự cố ứng dụng của tôi. Hóa ra đó là mật khẩu chứa '#' đang bị cắt ngắn ở bước đó.
Asac

3
Đây nên là câu trả lời được lựa chọn. Tôi không biết tại sao mọi người lại phức tạp hóa mọi thứ với các câu trả lời khác hoặc với nội dung này về env >> / etc / môi trường. Chỉ cần nhấp nháy chỉnh sửa tốt vv / môi trường nếu bạn muốn các vars env này có sẵn trên toàn cầu: các thử nghiệm của tôi dường như xác nhận rằng các báo cáo xuất khẩu cho vv env trong / etc / môi trường có sẵn cho crontab và cho cả người dùng. VẤN ĐỀ: một lần nữa từ các thí nghiệm của tôi: có vẻ như các lọ env này KHÔNG MỞ RỘNG trong chính crontab! ... tức là chúng chỉ được mở rộng trong các tập lệnh được gọi!
mike gặm nhấm

39

Nếu bạn bắt đầu các tập lệnh bạn đang thực thi thông qua cron với:

#!/bin/bash -l

Họ nên chọn các ~/.bash_profilebiến môi trường của bạn


4
Câu trả lời này sẽ nhận được nhiều sự ủng hộ hơn và chỉ đơn giản là câu trả lời được chọn: Rất đơn giản và thanh lịch và tránh vô số các loại bùn sẽ yêu cầu nhảy khắp hệ thống.
JakeGould 14/12/18

Tôi thích câu trả lời này +1. Có thể / nên sử dụng cái này khi chạy rootcrontab không? Không có /home/rootthư mục trên hệ thống của tôi và vì vậy tôi không thấy cách này sẽ hoạt động với rootcrontab. Ý tưởng?
Seamus

Trong chính kịch bản. Mà sau đó bạn chạy với cron bình thường.
breizhmg

@Jim xem ví dụ này , sử dụng tệp thực thi cổ điển (chmod 777) #!/bin/bash. Điều kỳ diệu ở đây là thêm-l
Peter Krauss

22

Mở rộng trên ví dụ @carestad, mà tôi thấy dễ dàng hơn, là chạy tập lệnh với cron và có môi trường trong tập lệnh.

Trong tập tin crontab -e:

SHELL=/bin/bash

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

Trong tệp cron_job.sh:

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

Bất kỳ lệnh nào sau nguồn .bash_profile sẽ có môi trường của bạn như thể bạn đã đăng nhập.


16

Đối với tôi, tôi phải đặt biến môi trường cho ứng dụng php. Tôi đã gửi lại nó bằng cách thêm đoạn mã sau vào crontab của tôi.

$ sudo  crontab -e

crontab:

ENVIRONMENT_VAR=production

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

và bên trong doS SomethingWonderful.php Tôi có thể nhận giá trị môi trường với:

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

Tôi hi vọng cái này giúp được!


Điều này đã không làm việc cho tôi. Biến môi trường không có sẵn trong tập lệnh được gọi bên trong crontab.
Nikhil

12

Bất cứ điều gì bạn đặt vào crontabsẽ có sẵn trong các cronjobs, cả trực tiếp và sử dụng các biến trong tập lệnh.

Sử dụng chúng trong định nghĩa của cronjob

Bạn có thể định cấu hình crontabđể nó đặt các biến mà sau đó cronjob có thể sử dụng:

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

Bây giờ các tập tin /tmp/hellohiển thị những thứ như:

$ 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

Sử dụng chúng trong kịch bản được điều hành bởi cronjob

Bạn có thể cấu hình crontabđể nó đặt các biến mà sau đó các tập lệnh có thể sử dụng:

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

Và nói kịch bản /tmp/myscript.shlà như thế này:

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

Nó tạo ra một tập tin /tmp/myoutput.reshiển thị:

$ 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
...

7

Mở rộng trên @Robert Brisita vừa mới mở rộng, nếu bạn không muốn thiết lập tất cả các biến của cấu hình trong tập lệnh, bạn có thể chọn các biến để xuất trên đầu tập lệnh

Trong tập tin crontab -e:

SHELL=/bin/bash

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

Trong script.sh

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

some-other-command

7

Thay vì

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

Sử dụng bash -l -c

0  *  *  *  *  bash -l -c 'sh /my/script.sh'

1
Tại sao làm điều này thay vì chỉ có khai báo Bash ở đầu tệp có dạng -lnhư sau : #!/bin/bash -l? Câu trả lời khác là đơn giản và thanh lịch.
JakeGould

1
Điều gì xảy ra nếu tôi cần chạy một kịch bản perl / python / ruby ​​không bash? Tôi không thể thêm #! / Bin / bash -l vào đầu tập lệnh python.
Ilya Kharlamov

Nếu tôi cần chạy một kịch bản perl / python / ruby ​​không bash thì sao? Đủ công bằng. Nhưng trong tâm trí tôi, bạn có thể viết một trình bao bọc tập lệnh Bash đơn giản mà sau đó gọi tập lệnh Python. Tôi làm một điều tương tự cho các kịch bản PHP. Lý do là khóa quá trình tốt hơn và đáng tin cậy hơn ở Bash, nhưng kịch bản Bash vẫn là một vấn đề đau đầu. Vì vậy, tôi đã viết những thứ trong PHP cho những thứ phức tạp và để Bash xử lý phần còn lại.
JakeGould 14/12/18

3

Tôi đang sử dụng Oh-my-zshtrong macbook của mình vì vậy tôi đã thử nhiều thứ để chạy tác vụ crontab nhưng cuối cùng, giải pháp của tôi là chuẩn bị trước .zshrckhi lệnh chạy.

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

Nhiệm vụ này chạy cứ sau 30 phút và sử dụng .zshrc hồ sơ để thực thi lệnh nút của tôi.

Đừng quên sử dụng dấu chấm trước $HOMEvar.


2

Một cách khác - lấy cảm hứng từ câu trả lời này - để "tiêm" các biến là như sau (ví dụ fcron):

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

Từ help set:

-a Đánh dấu các biến được sửa đổi hoặc tạo để xuất.

Sử dụng + thay vì - làm cho các cờ này bị tắt.

Vì vậy, mọi thứ ở giữa set -set +được xuất sang envvà sau đó có sẵn cho các tập lệnh khác, v.v. Không sử dụng setcác biến sẽ có nguồn gốc nhưng sống trongset .

Ngoài ra, việc truyền các biến khi chương trình yêu cầu tài khoản không phải root cũng rất hữu ích nhưng bạn cần một số biến trong môi trường người dùng khác. Dưới đây là một ví dụ chuyển qua vars nullmailer để định dạng tiêu đề e-mail:

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

2

Tôi đã thử hầu hết các giải pháp được cung cấp, nhưng không có gì hiệu quả lúc đầu. Tuy nhiên, hóa ra đó không phải là giải pháp không hiệu quả. Rõ ràng, ~/.bashrctệp của tôi bắt đầu với khối mã sau:

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

Điều này về cơ bản là case statementkiểm tra tập hợp các tùy chọn hiện tại trong trình bao hiện tại để xác định rằng trình bao đang chạy tương tác. Nếu shell xảy ra để chạy tương tác, thì nó chuyển sang tìm nguồn cung cấp ~/.bashrctệp. Tuy nhiên, trong một vỏ được gọi bởi cron, $-biến không chứa igiá trị biểu thị tính tương tác. Do đó, các ~/.bashrctập tin không bao giờ có nguồn gốc đầy đủ. Kết quả là, các biến môi trường không bao giờ được thiết lập. Nếu đây là vấn đề của bạn, vui lòng bình luận khối mã như sau và thử lại:

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

Tôi hy vọng điều này hóa ra hữu ích


0

Bạn cũng có thể thêm lệnh của mình envđể tiêm biến môi trường như sau:

0 * * * *   env VARIABLE=VALUE /usr/bin/mycommand
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.