ปกติฉันมีปัญหาหลายอย่างเกี่ยวกับวิธีที่ cron เรียกใช้งานสคริปต์เนื่องจากปกติไม่มีการตั้งค่าสภาพแวดล้อมของฉัน มีวิธีในการเรียกใช้ bash (?) ในลักษณะเดียวกับ cron หรือไม่ดังนั้นฉันจึงสามารถทดสอบสคริปต์ก่อนติดตั้งได้หรือไม่
ปกติฉันมีปัญหาหลายอย่างเกี่ยวกับวิธีที่ cron เรียกใช้งานสคริปต์เนื่องจากปกติไม่มีการตั้งค่าสภาพแวดล้อมของฉัน มีวิธีในการเรียกใช้ bash (?) ในลักษณะเดียวกับ cron หรือไม่ดังนั้นฉันจึงสามารถทดสอบสคริปต์ก่อนติดตั้งได้หรือไม่
คำตอบ:
เพิ่มลงใน crontab ของคุณ (ชั่วคราว):
* * * * * env > ~/cronenv
หลังจากทำงานให้ทำดังนี้
env - `cat ~/cronenv` /bin/sh
สิ่งนี้จะถือว่า cron ของคุณรัน / bin / sh ซึ่งเป็นค่าเริ่มต้นโดยไม่คำนึงถึงเชลล์เริ่มต้นของผู้ใช้
env -
แมว ~ / cronenv` / bin / sh` ควรจะเขียนเป็นงาน cron ยัง? โปรดยกตัวอย่าง
Cron จัดเตรียมสภาพแวดล้อมนี้เป็นค่าเริ่มต้นเท่านั้น:
HOME
โฮมไดเรกทอรีของผู้ใช้LOGNAME
เข้าสู่ระบบของผู้ใช้PATH=/usr/bin:/usr/sbin
SHELL=/usr/bin/sh
หากคุณต้องการมากกว่านี้คุณสามารถระบุสคริปต์ที่คุณกำหนดสภาพแวดล้อมของคุณก่อนตารางการกำหนดเวลาใน crontab
สองแนวทาง:
ส่งออก cron env และหาแหล่งที่มา:
เพิ่ม
* * * * * env > ~/cronenv
ไปที่ crontab ของคุณปล่อยให้มันรันหนึ่งครั้งปิดมันแล้วเรียกใช้
env - `cat ~/cronenv` /bin/sh
และตอนนี้คุณอยู่ในsh
เซสชั่นที่มีสภาพแวดล้อมของ cron
นำสภาพแวดล้อมของคุณไปสู่ cron
คุณสามารถข้ามการออกกำลังกายข้างต้นและทำ. ~/.profile
หน้างาน cron ของคุณเช่น
* * * * * . ~/.profile; your_command
ใช้หน้าจอ
โซลูชันสองตัวข้างต้นยังคงล้มเหลวเนื่องจากมีสภาพแวดล้อมที่เชื่อมต่อกับเซสชัน X ที่กำลังทำงานอยู่โดยมีการเข้าถึงdbus
เป็นต้นตัวอย่างเช่นบน Ubuntu nmcli
(ตัวจัดการเครือข่าย) จะทำงานในสองวิธีข้างต้น แต่ยังคงล้มเหลวใน cron
* * * * * /usr/bin/screen -dm
เพิ่มบรรทัดด้านบนเพื่อ cron ให้มันทำงานครั้งเดียวปิดมันกลับ เชื่อมต่อกับเซสชันหน้าจอของคุณ (screen -r) หากคุณกำลังตรวจสอบเซสชั่นหน้าจอถูกสร้างขึ้น (พร้อมps
) โปรดระวังว่าบางครั้งพวกเขาจะอยู่ในเมืองหลวง (เช่นps | grep SCREEN
)
แม้ตอนนี้nmcli
และที่คล้ายกันจะล้มเหลว
คุณสามารถเรียกใช้:
env - your_command arguments
สิ่งนี้จะเรียกใช้ your_command ด้วยสภาพแวดล้อมที่ว่างเปล่า
env - HOME="$HOME" LOGNAME="$USER" PATH="/usr/bin:/bin" SHELL="$(which sh)" command arguments
ซึ่งดูเหมือนว่าจะทำเคล็ดลับ
ขึ้นอยู่กับเปลือกของบัญชี
sudo su
env -i /bin/sh
หรือ
sudo su
env -i /bin/bash --noprofile --norc
จากhttp://matthew.mceachen.us/blog/howto-simulate-the-cron-environment-1018.html
ตอบหกปีต่อมา: ปัญหาสิ่งแวดล้อมไม่ตรงกันเป็นหนึ่งในปัญหาที่แก้ไขได้โดยsystemd
"ตัวจับเวลา" เป็นการแทนที่ cron ไม่ว่าคุณจะเรียกใช้ systemd "service" จาก CLI หรือผ่าน cron จะได้รับสภาพแวดล้อมเดียวกันทุกประการโดยหลีกเลี่ยงปัญหาสภาพแวดล้อมที่ไม่ตรงกัน
ปัญหาที่พบบ่อยที่สุดในการทำให้งาน cron ล้มเหลวเมื่อพวกเขาส่งด้วยตนเองคือข้อ จำกัด เริ่มต้นที่$PATH
กำหนดโดย cron ซึ่งเป็นสิ่งนี้ใน Ubuntu 16.04:
"/usr/bin:/bin"
ในทางตรงกันข้ามค่าเริ่มต้นที่$PATH
กำหนดโดยsystemd
บน Ubuntu 16.04 คือ:
"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
ดังนั้นจึงมีโอกาสที่ดีกว่าที่ตัวจับเวลา systemd จะค้นหาไบนารีโดยไม่มีความยุ่งยากเพิ่มขึ้น
ข้อเสียของตัวจับเวลา systemd คือมีเวลาอีกเล็กน้อยในการตั้งค่า คุณสร้างไฟล์ "บริการ" เพื่อกำหนดสิ่งที่คุณต้องการเรียกใช้และไฟล์ "ตัวจับเวลา" เพื่อกำหนดตารางเวลาเพื่อเรียกใช้งานและในที่สุดก็ "เปิดใช้งาน" ตัวจับเวลาเพื่อเปิดใช้งาน
สร้างงาน cron ที่รัน env และเปลี่ยนทิศทาง stdout ไปยังไฟล์ ใช้ไฟล์ข้าง "env -" เพื่อสร้างสภาพแวดล้อมเดียวกันกับงาน cron
อย่าลืมว่าเนื่องจาก parent cron เป็น init มันรันโปรแกรมโดยไม่มีเทอร์มินัลการควบคุม คุณสามารถจำลองด้วยเครื่องมือเช่นนี้:
โดยค่าเริ่มต้นcron
ดำเนินงานโดยใช้สิ่งที่ระบบของคุณคิดว่าsh
เป็น ซึ่งอาจเป็นจริง Bourne เปลือกหรือdash
, ash
, ksh
หรือbash
(หรืออีกคนหนึ่ง) symlinked ไปsh
(และเป็นผลมาทำงานในโหมด POSIX)
สิ่งที่ดีที่สุดที่จะทำคือตรวจสอบให้แน่ใจว่าสคริปต์ของคุณมีสิ่งที่ต้องการและจะไม่มีสิ่งใดจัดเตรียมไว้สำหรับพวกเขา ดังนั้นคุณควรใช้ข้อมูลจำเพาะของไดเรกทอรีแบบเต็มและตั้งค่าตัวแปรสภาพแวดล้อมเช่น$PATH
ตัวคุณเอง
0 0 * * 1 /path/to/executable >/dev/null 2>&1
จากนั้นภายใน "ปฏิบัติการ" ฉันจะตั้งค่าสำหรับ$PATH
ฯลฯ และใช้รายละเอียดไดเรกทอรีเต็มไปยังไฟล์อินพุตและเอาต์พุต ฯลฯ ตัวอย่างเช่น:/path/to/do_something /another/path/input_file /another/path/to/output_file
วิธีง่ายๆอีกวิธีหนึ่งที่ฉันพบ (แต่อาจมีข้อผิดพลาดเกิดขึ้นฉันยังทดสอบอยู่) คือการระบุไฟล์โปรไฟล์ของผู้ใช้ของคุณก่อนคำสั่งของคุณ
การแก้ไขสคริปต์ /etc/cron.d/:
* * * * * user1 comand-that-needs-env-vars
จะกลายเป็น:
* * * * * user1 source ~/.bash_profile; source ~/.bashrc; comand-that-needs-env-vars
สกปรก แต่มันก็ทำให้ฉันทำงานเสร็จแล้ว มีวิธีจำลองการเข้าสู่ระบบหรือไม่? เพียงแค่คำสั่งที่คุณสามารถเรียกใช้? bash --login
ไม่ทำงาน ดูเหมือนว่าจะเป็นวิธีที่ดีกว่าที่จะไป
แก้ไข: นี่น่าจะเป็นทางออกที่มั่นคง: http://www.epicserve.com/blog/2012/feb/7/my-notes-cron-directory-etccrond-ubuntu-1110/
* * * * * root su --session-command="comand-that-needs-env-vars" user1 -l
คำตอบที่ยอมรับจะให้วิธีเรียกใช้สคริปต์กับ cron สภาพแวดล้อมที่จะใช้ ตามที่คนอื่นชี้ว่านี่ไม่ใช่เกณฑ์ที่จำเป็นเท่านั้นสำหรับการดีบักงาน cron
แท้จริงแล้ว cron ยังใช้เทอร์มินัลที่ไม่มีการโต้ตอบโดยไม่ต้องมีอินพุตที่ต่อพ่วง ฯลฯ
หากช่วยได้ฉันได้เขียนสคริปต์ที่เปิดใช้งานคำสั่ง / สคริปต์อย่างไม่ลำบากเช่น cron เรียกใช้พร้อมกับคำสั่ง / สคริปต์ของคุณเป็นอาร์กิวเมนต์แรกและคุณก็ทำได้
สคริปต์นี้ยังจะเป็นเจ้าภาพ (และอาจจะมีการปรับปรุง) บนGithub
#!/bin/bash
# Run as if it was called from cron, that is to say:
# * with a modified environment
# * with a specific shell, which may or may not be bash
# * without an attached input terminal
# * in a non-interactive shell
function usage(){
echo "$0 - Run a script or a command as it would be in a cron job, then display its output"
echo "Usage:"
echo " $0 [command | script]"
}
if [ "$1" == "-h" -o "$1" == "--help" ]; then
usage
exit 0
fi
if [ $(whoami) != "root" ]; then
echo "Only root is supported at the moment"
exit 1
fi
# This file should contain the cron environment.
cron_env="/root/cron-env"
if [ ! -f "$cron_env" ]; then
echo "Unable to find $cron_env"
echo "To generate it, run \"/usr/bin/env > /root/cron-env\" as a cron job"
exit 0
fi
# It will be a nightmare to expand "$@" inside a shell -c argument.
# Let's rather generate a string where we manually expand-and-quote the arguments
env_string="/usr/bin/env -i "
for envi in $(cat "$cron_env"); do
env_string="${env_string} $envi "
done
cmd_string=""
for arg in "$@"; do
cmd_string="${cmd_string} \"${arg}\" "
done
# Which shell should we use?
the_shell=$(grep -E "^SHELL=" /root/cron-env | sed 's/SHELL=//')
echo "Running with $the_shell the following command: $cmd_string"
# Let's route the output in a file
# and do not provide any input (so that the command is executed without an attached terminal)
so=$(mktemp "/tmp/fakecron.out.XXXX")
se=$(mktemp "/tmp/fakecron.err.XXXX")
"$the_shell" -c "$env_string $cmd_string" >"$so" 2>"$se" < /dev/null
echo -e "Done. Here is \033[1mstdout\033[0m:"
cat "$so"
echo -e "Done. Here is \033[1mstderr\033[0m:"
cat "$se"
rm "$so" "$se"
คำตอบhttps://stackoverflow.com/a/2546509/5593430แสดงวิธีรับสภาพแวดล้อม cron และใช้กับสคริปต์ของคุณ แต่ระวังว่าสภาพแวดล้อมอาจแตกต่างกันไปขึ้นอยู่กับไฟล์ crontab ที่คุณใช้ ฉันสร้างสามรายการ cron env > log
ที่แตกต่างกันในการรักษาสิ่งแวดล้อมผ่าน สิ่งเหล่านี้เป็นผลลัพธ์ของ Amazon Linux 4.4.35-33.55.amzn1.x86_64
MAILTO=root
SHELL=/bin/bash
USER=root
PATH=/sbin:/bin:/usr/sbin:/usr/bin
PWD=/
LANG=en_US.UTF-8
SHLVL=1
HOME=/
LOGNAME=root
_=/bin/env
crontab -e
)SHELL=/bin/sh
USER=root
PATH=/usr/bin:/bin
PWD=/root
LANG=en_US.UTF-8
SHLVL=1
HOME=/root
LOGNAME=root
_=/usr/bin/env
MAILTO=root
SHELL=/bin/bash
USER=root
PATH=/sbin:/bin:/usr/sbin:/usr/bin
_=/bin/env
PWD=/
LANG=en_US.UTF-8
SHLVL=3
HOME=/
LOGNAME=root
ที่สำคัญที่สุดPATH
, PWD
และHOME
แตกต่างกัน ตรวจสอบให้แน่ใจว่าตั้งค่าเหล่านี้ในสคริปต์ cron ของคุณให้ใช้สภาพแวดล้อมที่มั่นคง
ฉันไม่เชื่อว่ามี; วิธีเดียวที่ฉันรู้ว่าจะทดสอบงาน cron คือการตั้งค่าให้ทำงานหนึ่งหรือสองนาทีในอนาคตแล้วรอ