ฉันจะตั้งค่าตัวแปรสภาพแวดล้อมที่ crontab จะใช้ได้อย่างไร


266

ฉันมี crontab ทำงานทุกชั่วโมง ผู้ใช้ที่ใช้งานนั้นมีสภาพแวดล้อมที่หลากหลายในการ.bash_profileทำงานเมื่อผู้ใช้เรียกใช้งานจากเทอร์มินัลอย่างไรก็ตามเห็นได้ชัดว่าสิ่งเหล่านี้ไม่ได้รับโดย crontab เมื่อทำงาน

ฉันลองตั้งค่า.profileแล้ว.bashrcแต่พวกเขายังดูเหมือนจะไม่ไปรับ ไม่มีใครรู้ว่าฉันสามารถวาง vars สภาพแวดล้อมที่ crontab สามารถรับได้หรือไม่

คำตอบ:


88

ให้ 'cron' เรียกใช้เชลล์สคริปต์ที่ตั้งค่าสภาพแวดล้อมก่อนรันคำสั่ง

เสมอ.

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

สคริปต์ใน ~ / bin / Cron คือลิงก์ทั้งหมดไปยังสคริปต์เดียว 'runcron' ซึ่งมีลักษณะดังนี้:

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

(เขียนโดยใช้มาตรฐานการเข้ารหัสที่เก่ากว่า - ทุกวันนี้ฉันจะใช้ shebang '#!' ตอนเริ่มต้น)

'~ / .cronfile' เป็นรูปแบบต่าง ๆ ในโปรไฟล์ของฉันสำหรับใช้งานโดย cron - ไม่โต้ตอบอย่างจริงจังและไม่มีเสียงสะท้อนเพื่อเสียงดัง คุณสามารถจัดเรียงเพื่อดำเนินการ. profile และอื่น ๆ แทน (สิ่งที่ REAL_HOME เป็นสิ่งประดิษฐ์ของสภาพแวดล้อมของฉัน - คุณสามารถทำเป็นว่ามันเหมือนกับ $ HOME)

ดังนั้นรหัสนี้อ่านสภาพแวดล้อมที่เหมาะสมและดำเนินการคำสั่งรุ่นที่ไม่ใช่ Cron จากไดเรกทอรีบ้านของฉัน ตัวอย่างเช่นคำสั่ง 'วันทำงาน' ของฉันดูเหมือน:

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

# Update ICSCOPE
n.updics

คำสั่ง 'รายวัน' นั้นง่ายกว่า:

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

คุณสามารถกำหนดตัวแปรสภาพแวดล้อมใน crontab ของตัวเองเมื่อทำงานcrontab -eจากบรรทัดคำสั่ง

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

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

คุณลักษณะนี้มีให้สำหรับการใช้งาน cron บางอย่างเท่านั้น ปัจจุบัน Ubuntu และ Debian ใช้vixie-cronซึ่งทำให้สามารถประกาศได้ในไฟล์ crontab (เช่น GNU mcron )

ArchLinuxและRedHatใช้cronieซึ่งไม่อนุญาตให้ตัวแปรสภาพแวดล้อมที่จะได้รับการประกาศและจะโยนความผิดพลาดในไวยากรณ์ cron.log วิธีแก้ปัญหาสามารถทำได้ต่อหนึ่งรายการ:

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

58
โปรดทราบว่าคุณไม่สามารถใช้การทดแทนตัวแปรได้เช่นเดียวกับเชลล์ดังนั้นการประกาศเช่น PATH = / usr / local / bin: $ PATH ถูกตีความอย่างแท้จริง
Zac

8
ฉันสามารถตั้งค่าตัวแปรสภาพแวดล้อมใน crontab ภายใต้ RedHat 4.4.7-3 และ cronie-1.4.4-15.el6.x86_64
Bruno Lange

7
คุณไม่จำเป็นต้องส่งออกตัวแปรหากมีการใช้ตัวแปรภายในคำสั่งเพียงเตรียมพารามิเตอร์ไว้ก่อนคำสั่งของคุณ "* * * * * 5s สลีป; LC_ALL = nb_NO.UTF-8 echo $ LC_ALL"
vutran


@BrunoLange คุณสามารถแชร์สิ่งที่คุณจัดการได้อย่างไร
Newskooler

145

ฉันได้ทางออกอีกหนึ่งข้อสำหรับปัญหานี้:

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

ในกรณีนี้มันจะเลือกตัวแปรสภาพแวดล้อมทั้งหมดที่กำหนดไว้ใน$HOME/.profileไฟล์ของคุณ

แน่นอนนอกจากนี้ยังไม่ได้ตั้งค่าที่คุณต้องแทนที่ด้วยเส้นทางแบบเต็มของคุณ$HOME$HOME


สิ่งนี้ใช้ได้กับฉันหลังจากที่ต้องดิ้นรนมากเพื่อหาคำตอบขอบคุณ!
vladimir montealegre

5
สิ่งนี้ไม่ได้ผลสำหรับฉันจนกว่าฉันจะรู้ว่าฉันได้ละทิ้งช่วงเวลาก่อนหน้า $ HOME ยุคนั้นทำอะไรกันแน่?
flymike

9
ช่วงเวลานี้เทียบเท่ากับคำสั่ง "แหล่งที่มา": tldp.org/LDP/abs/html/special-chars.html#DOTREF
Jeff W

@PeterLee มีการกล่าวถึงสิ่งใดที่ได้ผลสำหรับคุณ ฉันเขียนสิ่งนี้เนื่องจากวิธีแก้ปัญหาที่กล่าวถึงข้างต้นไม่มีประสิทธิภาพสำหรับฉัน หากวิธีการดังกล่าวไม่ทำงานฉันจะต้องทำวิจัยเพื่อค้นหาเหตุผล ;-)
Vishal

3
@Vishal จริงแล้วมันใช้ได้กับฉันแล้ว ฉันพยายามsource ~/.bashrcและปรากฎว่า.bashrcไฟล์ของฉันเรียงลำดับของความขัดแย้งกับงาน cron ถ้าฉันใช้.env_setup_rcไฟล์ที่ง่ายมากที่มีเพียงหนึ่งบรรทัด: export MY_ENV_VAR=my_env_valมันใช้งานได้จริง ดูโพสต์ของฉัน: stackoverflow.com/questions/15557777/…
Peter Lee

63

การตั้งค่า vars /etc/environmentยังใช้ได้กับฉันใน Ubuntu ด้วย ตั้งแต่ 12.04 ตัวแปร/etc/environmentถูกโหลดสำหรับ cron


11
คำตอบที่ดีที่สุดเพียงรันenv >> /etc/environmentและ env vars ปัจจุบันทั้งหมดมีอยู่ในงาน CRON
Savageman

6
มันใช้งานได้ดีสำหรับฉัน โดยเฉพาะอย่างยิ่งเพราะฉันทำงานใน Docker Container ดังนั้นฉันไม่สนใจอะไรเกี่ยวกับ "ความกว้างของระบบ"
Lucas Pottersky

14
@Savageman มันเหมือนกับการฆ่าแมลงวันด้วยระเบิดฟิวชั่นและสัดส่วนของพฤติกรรมที่ไม่คาดคิดนั้นสูงมาก
ฟราน Marzoa

2
ระวัง: env >> /etc/environmentจะล้มเหลวหากมีเครื่องหมายแฮชในหนึ่งในตัวแปรสภาพแวดล้อม ฉันมีเวลาที่ยากที่สุดในการแก้ไขปัญหาใบสมัครของฉัน มันกลายเป็นรหัสผ่านที่มี '#' ซึ่งถูกตัดทอนในขั้นตอนนั้น
asac

3
นี่ควรเป็นคำตอบที่เลือก ฉันไม่รู้ว่าทำไมผู้คนถึงสับสนกับคำตอบอื่น ๆ หรือสิ่งนี้เกี่ยวกับ env >> / etc / environment เพียงแค่กระพริบอย่างดีแก้ไข etc / environment หากคุณต้องการให้ env vars เหล่านี้สามารถใช้งานได้ในระดับสากล: การทดลองของฉันดูเหมือนจะยืนยันว่างบการส่งออกสำหรับ env vars ใน / etc / environment นั้นพร้อมใช้งานสำหรับ crontab และสำหรับผู้ใช้ ปัญหา: อีกครั้งจากการทดลองของฉัน: ดูเหมือนว่า env vars เหล่านี้จะไม่ถูกขยายภายใน crontab เอง! ... นั่นคือพวกเขาจะขยายเฉพาะในสคริปต์ที่เรียกว่า!
ไมค์หนู

39

หากคุณเริ่มต้นสคริปต์คุณกำลังดำเนินการผ่าน cron ด้วย:

#!/bin/bash -l

ควรเลือก~/.bash_profileตัวแปรสภาพแวดล้อมของคุณ


4
คำตอบนี้ควรได้รับการโหวตมากขึ้นและเป็นคำตอบที่เลือกง่ายและสวยงามและหลีกเลี่ยง kludges ที่นับไม่ถ้วนที่จะต้องกระโดดข้ามระบบ
JakeGould

ฉันชอบคำตอบนี้ +1 เป็นไปได้ / ควรใช้สิ่งนี้เมื่อเรียกใช้rootcrontab หรือไม่ ไม่มี/home/rootโฟลเดอร์ในระบบของฉันดังนั้นฉันจึงไม่เห็นว่าจะทำงานอย่างไรกับrootcrontab ของ ไอเดีย?
เชมัส

ในสคริปต์เอง ซึ่งคุณจะทำงานกับ cron ได้ตามปกติ
breizhmg

@ Jim ดูตัวอย่างนี้ , แฟ้มที่ปฏิบัติการคลาสสิก (chmod 777) #!/bin/bashการใช้งาน ความมหัศจรรย์ที่นี่คือการเพิ่ม-l
Peter Krauss

22

การขยายตัวอย่าง @carestad ซึ่งฉันค้นหาได้ง่ายขึ้นคือการเรียกใช้สคริปต์ด้วย cron และมีสภาพแวดล้อมในสคริปต์

ในไฟล์ crontab -e:

SHELL=/bin/bash

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

ในไฟล์ cron_job.sh:

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

คำสั่งใด ๆ หลังจากแหล่งที่มาของ. bash_profile จะมีสภาพแวดล้อมของคุณราวกับว่าคุณเข้าสู่ระบบ


16

สำหรับฉันฉันต้องตั้งค่าตัวแปรสภาพแวดล้อมสำหรับแอปพลิเคชัน php ฉัน resloved มันโดยการเพิ่มรหัสต่อไปนี้เพื่อ crontab ของฉัน

$ sudo  crontab -e

crontab:

ENVIRONMENT_VAR=production

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

และภายใน doSomethingWonderful.php ฉันสามารถรับค่าสภาพแวดล้อมด้วย:

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

ฉันหวังว่านี่จะช่วยได้!


สิ่งนี้ไม่ได้ผลสำหรับฉัน ตัวแปรสภาพแวดล้อมไม่พร้อมใช้งานในสคริปต์ที่ถูกเรียกใช้ภายใน crontab
Nikhil

12

สิ่งที่คุณตั้งค่าcrontabจะมีอยู่ใน cronjobs ทั้งโดยตรงและใช้ตัวแปรในสคริปต์

ใช้ในนิยามของ cronjob

คุณสามารถกำหนดค่าcrontabเพื่อให้มันตั้งค่าตัวแปรที่สามารถ cronjob ใช้:

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

ตอนนี้ไฟล์/tmp/helloจะแสดงสิ่งต่าง ๆ เช่น:

$ 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

ใช้ในสคริปต์รันโดย cronjob

คุณสามารถกำหนดค่าcrontabเพื่อให้มันตั้งค่าตัวแปรที่สคริปต์สามารถใช้:

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

และบอกว่าสคริปต์/tmp/myscript.shเป็นเช่นนี้:

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

มันสร้างไฟล์ที่/tmp/myoutput.resแสดง:

$ 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

การขยายบน @Robert Brisita เพิ่งขยายออกไปถ้าคุณไม่ต้องการตั้งค่าตัวแปรทั้งหมดของโปรไฟล์ในสคริปต์คุณสามารถเลือกตัวแปรที่จะส่งออกที่ด้านบนของสคริปต์

ในไฟล์ crontab -e:

SHELL=/bin/bash

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

ใน script.sh

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

some-other-command

7

แทน

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

ใช้ bash -l -c

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

1
ทำไมทำเช่นนี้แทนที่จะเป็นเพียงแค่มีการประกาศทุบตีที่ด้านบนของไฟล์ที่มีดัง-lเช่นนี้#!/bin/bash -l? คำตอบอื่น ๆนี้เรียบง่ายและสง่างาม
JakeGould

1
ถ้าฉันต้องการรันสคริปต์ perl / python / ruby ​​ไม่ต้องทุบตี? ฉันไม่สามารถเพิ่ม #! / bin / bash -l ไปด้านบนสุดของสคริปต์ไพ ธ อน
Ilya Kharlamov

“ ถ้าฉันต้องรันสคริปต์ perl / python / ruby ​​ไม่ต้องทุบตี?” ยุติธรรมพอสมควร แต่ในใจของฉันคุณสามารถเขียน wrapper สคริปต์ Bash ง่าย ๆ แล้วเรียกสคริปต์ Python ฉันทำสิ่งที่คล้ายกันสำหรับสคริปต์ PHP เหตุผลคือการล็อคกระบวนการดีกว่าและเชื่อถือได้มากใน Bash แต่การเขียนสคริปต์ Bash ยังคงเป็นเรื่องที่น่าปวดหัว ดังนั้นฉันจึงเขียนสิ่งต่าง ๆ ใน PHP สำหรับสิ่งที่ซับซ้อนและให้ Bash จัดการส่วนที่เหลือ
JakeGould

3

ฉันกำลังใช้Oh-my-zshใน macbook ของฉันดังนั้นฉันได้ลองหลายสิ่งหลายอย่างเพื่อให้งาน crontab ทำงาน แต่ในที่สุดโซลูชันของฉันก็กำลัง.zshrcเตรียมคำสั่งก่อนที่จะเรียกใช้

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

ภารกิจนี้รันทุก 30 นาทีและใช้งาน .zshrcโปรไฟล์เพื่อเรียกใช้งานคำสั่งโหนดของฉัน

อย่าลืมใช้จุดก่อน$HOMEวา


2

อีกวิธีหนึ่งซึ่งได้รับแรงบันดาลใจจากคำตอบนี้ - ถึง "ฉีด" ตัวแปรดังต่อไปนี้ (ตัวอย่าง fcron):

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

จากhelp set:

- ตัวแปร Mark ซึ่งแก้ไขหรือสร้างขึ้นเพื่อการส่งออก

การใช้ + แทน - ทำให้การตั้งค่าสถานะเหล่านี้ถูกปิด

ดังนั้นทุกสิ่งในระหว่างset -และset +ถูกส่งออกไปยังenvและพร้อมใช้งานสำหรับสคริปต์อื่น ๆ ฯลฯ โดยไม่ต้องใช้setตัวแปรจะได้รับที่มา แต่อาศัยอยู่ในsetเท่านั้น

นอกจากนั้นยังมีประโยชน์ในการส่งผ่านตัวแปรเมื่อโปรแกรมต้องการบัญชีที่ไม่ใช่รูทเพื่อให้ทำงานได้ แต่คุณต้องการตัวแปรบางอย่างภายในสภาพแวดล้อมของผู้ใช้รายอื่น ด้านล่างเป็นตัวอย่างที่ส่งผ่าน vars nullmailer เพื่อจัดรูปแบบส่วนหัวของอีเมล:

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

2

ฉันลองใช้วิธีแก้ปัญหาส่วนใหญ่แล้ว แต่ไม่มีอะไรทำงานในตอนแรก มันกลับกลายเป็นว่ามันไม่ใช่ทางออกที่ล้มเหลวในการทำงาน เห็นได้ชัดว่า~/.bashrcไฟล์ของฉันเริ่มต้นด้วยรหัสต่อไปนี้:

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

นี่เป็นพื้นที่case statementตรวจสอบชุดตัวเลือกปัจจุบันในเชลล์ปัจจุบันเพื่อตรวจสอบว่าเชลล์กำลังทำงานแบบโต้ตอบ หากเชลล์เกิดการทำงานแบบโต้ตอบมันจะย้ายไปยังการจัดหา~/.bashrcไฟล์ อย่างไรก็ตามในเปลือกเรียกโดยcronที่$-ตัวแปรไม่ได้มีiค่าซึ่งบ่งบอกถึงการติดต่อสื่อสาร ดังนั้น~/.bashrcไฟล์ไม่เคยได้รับที่มาอย่างเต็มที่ ส่งผลให้ตัวแปรสภาพแวดล้อมไม่เคยถูกตั้งค่า หากสิ่งนี้เป็นปัญหาของคุณอย่าลังเลที่จะคอมเม้นต์บล็อกของรหัสดังต่อไปนี้และลองอีกครั้ง:

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

ฉันหวังว่าสิ่งนี้จะเป็นประโยชน์


0

นอกจากนี้คุณยังสามารถเติมคำสั่งของคุณด้วยenvเพื่อฉีดตัวแปรสภาพแวดล้อมเช่น:

0 * * * *   env VARIABLE=VALUE /usr/bin/mycommand
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.