ฉันจะรันคำสั่ง cron ด้วยตัวแปรสภาวะแวดล้อมที่มีอยู่ได้อย่างไร?


114

ฉันจะรันคำสั่ง cron ด้วยตัวแปรสภาวะแวดล้อมที่มีอยู่ได้อย่างไร?

ถ้าฉันอยู่ที่พรอมต์เชลล์ฉันสามารถพิมพ์echo $ORACLE_HOMEและรับเส้นทาง ~/.profileนี้เป็นหนึ่งในตัวแปรด้านสิ่งแวดล้อมของฉันที่ได้รับการตั้งค่าในของฉัน อย่างไรก็ตามดูเหมือน~/.profileว่าไม่ได้โหลดสคริปต์ fron cron และสคริปต์ของฉันล้มเหลวเนื่องจาก$ORACLE_HOMEไม่ได้ตั้งค่าตัวแปร

ในคำถามนี้ผู้เขียนกล่าวถึงการสร้าง~/.cronfileโปรไฟล์ที่ตั้งค่าตัวแปรสำหรับ cron แล้วเขาก็หาวิธีแก้ปัญหาเพื่อโหลดคำสั่ง cron ทั้งหมดของเขาลงในสคริปต์ที่เขาเก็บไว้ใน~/Cronไดเรกทอรีของเขา ไฟล์เช่น~/.cronfileเสียงดูเหมือนเป็นความคิดที่ดี แต่คำตอบที่เหลือดูเหมือนจะยุ่งยากเล็กน้อยและฉันก็หวังว่าจะมีคนบอกวิธีที่ง่ายกว่าในการได้รับผลลัพธ์เดียวกัน

ฉันคิดว่าเมื่อเริ่มต้นสคริปต์ของฉันฉันสามารถเพิ่มสิ่งที่ชอบsource ~/.profileแต่ที่ดูเหมือนว่ามันจะซ้ำซ้อน

ดังนั้นฉันจะทำให้สคริปต์ cron ของฉันโหลดตัวแปรจากโปรไฟล์ interactive-shell ได้อย่างไร


การเพิ่มsource ~/.profileโปรแกรมซ้ำซ้อนเป็นอย่างไร โปรแกรมสืบทอดสภาพแวดล้อมจากโปรแกรมที่เรียกใช้ หากโปรแกรมการโทรนั้นไม่ใช่เชลล์ของคุณดังนั้นโปรแกรม decendant จะได้รับสภาพแวดล้อมที่คุณต้องการอย่างไร
Arcege

ฉันได้เขียนคำตอบของคำถามที่คล้ายกันที่นี่แล้ว มันใช้su -lเพื่อตั้งค่าสภาพแวดล้อมการเข้าสู่ระบบปกติรวมถึง $ PATH สำหรับผู้ใช้รูทหรือผู้ใช้รายอื่น
tasket

คำตอบ:


141

ใน crontab . $HOME/.profileก่อนที่คุณจะสั่งเพิ่ม ตัวอย่างเช่น:

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

Cronไม่รู้อะไรเกี่ยวกับเปลือกของคุณ มันเริ่มโดยระบบดังนั้นจึงมีสภาพแวดล้อมที่น้อยที่สุด หากคุณต้องการอะไรคุณต้องมีสิ่งนั้นมาด้วยตัวเอง


14
อะไร.ก่อนสคริปต์ทำอย่างไร (ไม่แน่ใจว่าฉันจะทำอย่างไรman) ทำไมถึงแตกต่างจากsource?
cwd

25
คำสั่งเป็นคำสั่งเดิม. sourceพวกมันเทียบเท่ากันภายในเปลือกและพิมพ์ได้ง่ายกว่าเล็กน้อยโดยเฉพาะภายใน crontab เพื่อรับข้อมูลเพิ่มเติมพิมพ์help .หรือค้นหา^SHELL BUILTIN COMMANDSในหน้าคนสำหรับbashหรือที่ด้านบนของประเภทman zshbuiltins. ' . Running จะบอกคุณว่าคำสั่งเป็น builtin
Arcege

9
ทั้งนี้ขึ้นอยู่กับลินุกซ์, คุณอาจต้องเปลี่ยนจาก.profile .bash_profileตรวจสอบ.profileไฟล์ที่มีอยู่ในไดเรกทอรีบ้านของผู้ใช้
Frosty Z

@Arcege นี่ใช้ไม่ได้กับฉัน (Fedora Core 21) และฉันคิดว่าเป็นเพราะระดับกระสุนลดลง สิ่งที่ใช้ได้คือถ้าคุณให้มา
ริชาร์ด T

3
อาจเป็นไปได้ว่าถ้ามันไม่ทำงานอาจเป็นเพราะ SHELL สำหรับสคริปต์ cron ไม่ได้ถูกตั้งค่าเป็นทุบตีดังนั้นจึงไม่ได้ดำเนินการแบบเดียวกับที่คุณคาดหวัง
Daniel Farrell

40

ตัวเลือกอื่นที่ฉันพบได้ง่ายกว่าคือการเรียกใช้สคริปต์ด้วย 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 จะมีสภาพแวดล้อมของคุณราวกับว่าคุณเข้าสู่ระบบ


5
เมื่อทำงานบน AWS Linux AMI มันไม่ได้เกิดขึ้นกับฉันเลยที่ cron จะไม่ใช้/bin/bashเป็นเชลล์ ฉันยังคงสงสัยว่าทำไมสิ่งต่าง ๆ เช่นcd /path/to/project; source .varsจะทำงานเมื่อฉันพิมพ์ด้วยตนเอง แต่จะล้มเหลว ( File not found) เมื่อรวมอยู่ใน cronjob กุญแจสำคัญสำหรับฉันคือการตั้งค่าSHELL=/bin/bashเพื่อให้ฉันสามารถใช้คำสั่งทุบตีที่คุ้นเคยในแต่ละ cronjob /bin/sh/(เห็นได้ชัดว่า cron shell เริ่มต้น) มีข้อ จำกัด มาก
Hartley Brody

มันแย่มากที่คุณไม่สามารถระบุไฟล์สภาพแวดล้อมที่ด้านบนของ cron เช่นคุณสามารถระบุตัวแปรสภาพแวดล้อมแต่ละรายการได้ Systemd มีEnvironmentFileหน่วยบริการ cron ที่แย่เกินไปไม่มีอะไรที่คล้ายกัน
radtek

คุณบังคับให้สคริปต์ทั้งหมดใช้ / bin / bash ใน crontab ทั้งหมดซึ่งไม่ใช่ความคิดที่ดีรวมถึง cron line ของคุณ: * / 1 * * * * $ HOME / cron_job.sh … * / 1 เป็นสิ่งที่ดีสำหรับสิ่งที่ ?!? ดาวดวงหนึ่งหมายความว่าจะถูกประหารชีวิตทุกนาที / 1 หมายถึงจะถูกประหารชีวิตทุกนาทีเนื่องจากคำตอบในชุมชนที่ฉลาดนี่เป็นบาปที่น่ารังเกียจตอนนี้ฉันเชื่อว่าคุณสับสนมากที่จะพูดสิ่งที่ดีที่สุด ... ขออภัย
THESorcerer

1
นี่คือสิ่งที่เรียกว่าตัวอย่าง รู้สึกอิสระที่จะปรับให้เข้ากับความต้องการของคุณหรือไม่ได้ใช้เลย จังหวะที่แตกต่างกันสำหรับคนที่แตกต่างกัน
Robert Brisita

4
ถ้า$SHELLเป็น/bin/shเช่นนั้นsourceคำสั่งจะไม่มีอยู่ ใช้.แทน
Melle

18

ตัวเลือกอื่นที่ฉันพบได้ง่ายกว่าคือการเรียกใช้สคริปต์ด้วย cron และบอก bash เพื่อเข้าสู่ระบบ (ด้วยการใช้/etc/profile.d/...คำจำกัดความของสภาพแวดล้อม)

ในcrontab -eไฟล์:

*/1 * * * * bash -l -c './cron_job.sh'
*/1 * * * * bash -l -c 'php -f ./cron_job.php'

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


10

ความคิดที่ไม่ดี การปฏิบัติทั่วไปคือการตั้งค่าตัวแปรสภาพแวดล้อมที่จำเป็นทั้งหมดในสคริปต์ที่จะเรียกใช้จากงาน cron โดยเฉพาะ


ฉันเห็นด้วยกับ @fpmurphy ซึ่งเป็นวิธีที่ทำให้มั่นใจได้ถึงสภาพแวดล้อมของกระบวนการที่ปลอดภัย หากคุณต้องการตั้งค่าตัวแปรเพียงไม่กี่ตัวจาก cron คุณสามารถใช้/usr/bin/envคำสั่งเพื่อตั้งค่าตัวแปรและจากนั้นสามารถทำหน้าที่เป็นกระบวนการสภาพแวดล้อมสำหรับ cronjob
Nikhil Mulley

daemontoolsenvdirก็นึกขึ้นได้เช่นกัน
sr_

6
ฉันทั้งหมดเพื่อความปลอดภัย แต่บางทีฉันสามารถสร้างไฟล์~/.cronvarsและรวมไว้ในโปรไฟล์และในสคริปต์ cron ของฉัน ฉันไม่ต้องการตัวแปรตัวแปรสภาพแวดล้อมของรหัสยากในสคริปต์แต่ละตัวที่ฉันเรียกใช้เพราะเมื่อเส้นทางเปลี่ยนเส้นทางที่กำหนดรหัสยากในแต่ละไฟล์จะไม่สามารถดูแลรักษาได้ง่าย ดูเหมือนว่าจะช่วยให้สถานที่รวมศูนย์สำหรับตัวแปรที่ต้องการและยังคงป้องกันไม่ให้โหลดตัวแปรอื่น ๆ
cwd

4

ไวยากรณ์นี้ช่วยคุณได้แน่นอน ฉันไม่เข้าใจไวยากรณ์ แต่ใช้งานได้ Oracle ใช้ไวยากรณ์นี้เมื่อปรับใช้ Oracle Configuration Manager เป็น crontab ดังนั้นฉันเชื่อว่านี่เป็นโซลูชันที่เหมาะสม

0 5 * * * SOME_ENV_VAR=some_value some_command some_parameters

2

ฉันเพิ่งเจอกรณีที่ฉันต้องรัน cronjob โดยรวมเป็น root แต่ในเวลาเดียวกันต้องรันคำสั่งย่อยในฐานะผู้ใช้อื่น (ซึ่งจำเป็นต้องจัดหาสภาพแวดล้อมของผู้ใช้นั้น) ฉันใช้วิธีต่อไปนี้:

# m  h  dom  mon  dow  user  command
*/5  *   *    *    *   root  (sudo -i -u <the user> command-to-be-run-as-user) && command-to-be-run-as-root

ส่วนที่สำคัญคืออาร์กิวเมนต์-iที่ถูกส่งผ่านsudoซึ่งจะดำเนินการคำสั่งที่กำหนดในเชลล์การเข้าสู่ระบบที่แยกต่างหาก

PS: โปรดทราบว่าuserคอลัมน์นี้มีเฉพาะใน/etc/crontabและ/etc/cron.d/*ไฟล์เท่านั้น


1

วิธีการแก้ปัญหาที่ทำงานสำหรับฉันอธิบายไว้ที่นี่

คุณสร้างสคริปต์ตัวตัดคำซึ่งเรียกใช้. ~/.cronfileจากนั้นทำสิ่งที่คุณต้องการ สคริปต์นี้เปิดตัวโดย cron

ใน~/.cronfileคุณระบุสภาพแวดล้อมสำหรับงาน cron ของคุณ


1

ใช่คุณสามารถใช้ "วิธีแก้ปัญหาที่รู้จักกันดี" (มีอยู่สองรายการที่ระบุไว้) นี่เป็นอีกวิธีหนึ่งในการบอกว่าทุกคนรู้ว่ามันเส็งเคร็งแม้ว่าบางคนจะอ้างถึงสิ่งนี้ว่าเป็น "คุณลักษณะด้านความปลอดภัย" เพราะพวกเขาใช้เวลาอย่างน้อยก็มากที่จะสะดุดความล้มเหลวนี้ (คุณ) และต้องการคิด เวลาที่สูญเปล่าไม่ได้เป็นสิ่งใด มันเทียบเท่า cron ของคีย์บอร์ด QWERTY

ฉันสงสัยว่าเหตุผลดั้งเดิมอาจเป็นเพราะการทำงานเช่นว่าสคริปต์จะทำงานหนึ่งนาทีต่อนาทีจะไม่ใช้เวลาในการอ่านสคริปต์ rc แต่เดิม cron ไม่สามารถกำหนดค่าได้เลยดังนั้นค่าเริ่มต้นจึงเป็นตัวเลือกเดียวเท่านั้น

ไม่มีการรักษาความปลอดภัยเพิ่มเติมโดยไม่ต้องมีการกำหนดค่าหรือวิธีการที่ cron ง่ายที่จะใช้ในสภาพแวดล้อมของเปลือกโต้ตอบของคุณแทนผู้ใช้ที่ต้องทำยิมนาสติกเปลือกโง่ บนเครื่องที่ทันสมัยไม่มีการรับรู้ประสิทธิภาพโดยทั่วไปยกเว้นว่าคุณมีงานจำนวนมากที่ทำงานอยู่ทุกนาที

วัฒนธรรม Unix ล้มเหลว ในความเห็น "ต่ำต้อย" ของฉัน :-)


1
"ไม่มีความปลอดภัยเพิ่มเติม" นั่นไม่เป็นความจริง ลองดูที่CVE-2011-1095 , CVE-2008-4304และCVE-2010-3847

ฉันลงคะแนนคำตอบของคุณโดยวิธี ฉันมักจะพยายามหลีกเลี่ยงการลงคะแนนคำตอบของผู้มาใหม่ แต่ความปลอดภัยเป็นสิ่งสำคัญสำหรับฉัน โปรดอย่าลงคะแนนผิดวิธี นอกจากส่วนที่เกี่ยวกับความปลอดภัยแล้วคำตอบของคุณยอดเยี่ยมและสมควรได้รับการโหวต คุณสามารถแก้ไขคำตอบได้ที่นี่หากต้องการ

ไม่มีสิ่งใดที่เกี่ยวข้องกับการให้ cron ใช้เชลล์กับชุดธงแบบโต้ตอบ นี่คือ FUD บริสุทธิ์ น่าเสียดายที่ฉันไม่สามารถลงคะแนนโหวตของคุณได้ สิ่งนี้อาจดูเหมือนเป็นเปลวไฟ แต่ก็น่าผิดหวังมากเมื่อผู้คนคิดว่ารถยนต์ที่มีสามล้อดีกว่าเพราะมีปัญหาด้านความปลอดภัยที่ต้องติดล้อที่สี่ มันไม่ใช่ ผู้คนขี่จักรยานสามล้อมานานจนลืมแล้วว่าเป็นไปได้ที่จะเพิ่มล้อที่สี่
Austin S.

ใส่อีกวิธีหนึ่ง: หากมีการใช้ห่วงพิเศษอื่น ๆ ตามที่ผู้ให้คำแนะนำคนอื่นแนะนำไว้พวกเขาจะไม่เข้าถึงช่องที่คุณพูดถึงได้อย่างไร "* * * * * exec bash -i -c LOCALE = ....... "
Austin S.

สิ่งนี้อ่านเหมือนพูดจาโผงผาง ฉันไม่เห็นด้วยซ้ำว่าจะตอบคำถามได้ที่ไหน แม้ว่าส่วนความปลอดภัยจะถูกลบออก @EvanTeitelman ฉันไม่เห็นว่าทำไมจึงสมควรได้รับการอัปโหลดเนื่องจากไม่ตอบคำถาม
Wildcard


1

PATHแทนที่จะรายละเอียดการตั้งค่าสิ่งที่ช่วยให้ฉันได้รับการตั้งค่า คำสั่งบางคำไม่สามารถใช้ได้ในสคริปต์ cron ของฉันเพราะPATHมันแตกต่างกัน

ENVIRONMENT=prod
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
*/30 * * * * /opt/myscript1.sh
*/30 * * * * /opt/myscript2.sh
*/30 * * * * /opt/myscript3.sh

การตั้งค่าPATHด้วยเส้นทางของคำสั่งช่วยฉันได้ ยิ่งไปกว่านั้นถ้าคุณสามารถใช้เทมเพลตและตรวจสอบความถูกต้องภายหลัง

ENVIRONMENT={{ENVIRONMENT}}
PATH={{PATH}}
*/30 * * * * /opt/myscript1.sh
*/30 * * * * /opt/myscript2.sh
*/30 * * * * /opt/myscript3.sh

การส่งตัวแปรให้แต่ละรายการดูยุ่งเหยิง


-1

ฉันใส่ . ~/.dbus/session-bus/*ที่ด้านบนสุดของสคริปต์ที่ฉันต้องการ :)


1
ยินดีต้อนรับสู่ U & L SE โปรดขยายคำตอบของคุณให้มากขึ้นเพื่อให้เป็นประโยชน์ต่อผู้อ่าน
Ramesh
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.