วิธีการจำลองสภาพแวดล้อม cron รันสคริปต์ด้วย?


253

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


ฉันขอแนะนำวิธีแก้ปัญหานี้: unix.stackexchange.com/questions/27289/…
rudi

เมื่อใช้ @gregseth อีกเล็กน้อยฉันได้แก้ปัญหานี้: unix.stackexchange.com/questions/27289/…
Robert Brisita

คำตอบ:


385

เพิ่มลงใน crontab ของคุณ (ชั่วคราว):

* * * * * env > ~/cronenv

หลังจากทำงานให้ทำดังนี้

env - `cat ~/cronenv` /bin/sh

สิ่งนี้จะถือว่า cron ของคุณรัน / bin / sh ซึ่งเป็นค่าเริ่มต้นโดยไม่คำนึงถึงเชลล์เริ่มต้นของผู้ใช้


5
หมายเหตุ: หากเพิ่มเข้าไปใน global / etc / crontab คุณจะต้องมีชื่อผู้ใช้ด้วย เช่น * * * * * รูต env> ~ / cronenv
Greg

10
ความคิดที่ดีเรียบง่าย สำหรับการใช้งานอย่างใจร้อน '* * * * *' เพื่อเรียกใช้ในนาทีถัดไปและอย่าลืมปิดอีกครั้งเมื่อคุณเล่นเสร็จแล้ว ;-)
Mads Buus

5
@Madsn หากต้องการกลับไปที่เปลือกทุบตีก่อนหน้าให้ลอง: exit
spkane

5
ไม่สามารถประเมินความสำคัญของคำตอบนี้ได้ คุณค่าของการรวมวรรคในหนังสือ
Xofo

1
เป็นenv - แมว ~ / cronenv` / bin / sh` ควรจะเขียนเป็นงาน cron ยัง? โปรดยกตัวอย่าง
JavaSa

61

Cron จัดเตรียมสภาพแวดล้อมนี้เป็นค่าเริ่มต้นเท่านั้น:

  • HOME โฮมไดเรกทอรีของผู้ใช้
  • LOGNAME เข้าสู่ระบบของผู้ใช้
  • PATH=/usr/bin:/usr/sbin
  • SHELL=/usr/bin/sh

หากคุณต้องการมากกว่านี้คุณสามารถระบุสคริปต์ที่คุณกำหนดสภาพแวดล้อมของคุณก่อนตารางการกำหนดเวลาใน crontab


7
.มักจะไม่ได้เป็นส่วนหนึ่งของPATHอีกต่อไปสำหรับเหตุผลด้านความปลอดภัย
l0b0

49

สองแนวทาง:

  1. ส่งออก cron env และหาแหล่งที่มา:

    เพิ่ม

    * * * * * env > ~/cronenv

    ไปที่ crontab ของคุณปล่อยให้มันรันหนึ่งครั้งปิดมันแล้วเรียกใช้

    env - `cat ~/cronenv` /bin/sh

    และตอนนี้คุณอยู่ในshเซสชั่นที่มีสภาพแวดล้อมของ cron

  2. นำสภาพแวดล้อมของคุณไปสู่ ​​cron

    คุณสามารถข้ามการออกกำลังกายข้างต้นและทำ. ~/.profileหน้างาน cron ของคุณเช่น

    * * * * * . ~/.profile; your_command
  3. ใช้หน้าจอ

    โซลูชันสองตัวข้างต้นยังคงล้มเหลวเนื่องจากมีสภาพแวดล้อมที่เชื่อมต่อกับเซสชัน X ที่กำลังทำงานอยู่โดยมีการเข้าถึงdbusเป็นต้นตัวอย่างเช่นบน Ubuntu nmcli(ตัวจัดการเครือข่าย) จะทำงานในสองวิธีข้างต้น แต่ยังคงล้มเหลวใน cron

    * * * * * /usr/bin/screen -dm

    เพิ่มบรรทัดด้านบนเพื่อ cron ให้มันทำงานครั้งเดียวปิดมันกลับ เชื่อมต่อกับเซสชันหน้าจอของคุณ (screen -r) หากคุณกำลังตรวจสอบเซสชั่นหน้าจอถูกสร้างขึ้น (พร้อมps) โปรดระวังว่าบางครั้งพวกเขาจะอยู่ในเมืองหลวง (เช่นps | grep SCREEN)

    แม้ตอนนี้nmcliและที่คล้ายกันจะล้มเหลว


22

คุณสามารถเรียกใช้:

env - your_command arguments

สิ่งนี้จะเรียกใช้ your_command ด้วยสภาพแวดล้อมที่ว่างเปล่า


4
cron ไม่ทำงานในสภาพแวดล้อมที่ว่างเปล่าใช่ไหม?
jldupont

2
gregseth ระบุตัวแปรที่รวมอยู่ในสภาพแวดล้อมโดย cron คุณสามารถรวมตัวแปรนั้นในบรรทัดคำสั่ง $ env - PATH = "$ PATH" คำสั่ง args
DragonFax

4
@DragonFax @dimba ฉันใช้env - HOME="$HOME" LOGNAME="$USER" PATH="/usr/bin:/bin" SHELL="$(which sh)" command argumentsซึ่งดูเหมือนว่าจะทำเคล็ดลับ
l0b0

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


13

ตอบหกปีต่อมา: ปัญหาสิ่งแวดล้อมไม่ตรงกันเป็นหนึ่งในปัญหาที่แก้ไขได้โดย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 คือมีเวลาอีกเล็กน้อยในการตั้งค่า คุณสร้างไฟล์ "บริการ" เพื่อกำหนดสิ่งที่คุณต้องการเรียกใช้และไฟล์ "ตัวจับเวลา" เพื่อกำหนดตารางเวลาเพื่อเรียกใช้งานและในที่สุดก็ "เปิดใช้งาน" ตัวจับเวลาเพื่อเปิดใช้งาน


10

สร้างงาน cron ที่รัน env และเปลี่ยนทิศทาง stdout ไปยังไฟล์ ใช้ไฟล์ข้าง "env -" เพื่อสร้างสภาพแวดล้อมเดียวกันกับงาน cron


ขอโทษที่ทำให้ฉันสับสน "env - script" ไม่เพียงพอหรือ
Jorge Vargas

ที่จะทำให้คุณมีสภาพแวดล้อมที่ว่างเปล่า เมื่อคุณเรียกใช้สคริปต์ผ่าน cron สภาพแวดล้อมจะไม่ว่างเปล่า
Jens Carlberg


2

โดยค่าเริ่มต้นcronดำเนินงานโดยใช้สิ่งที่ระบบของคุณคิดว่าshเป็น ซึ่งอาจเป็นจริง Bourne เปลือกหรือdash, ash, kshหรือbash(หรืออีกคนหนึ่ง) symlinked ไปsh(และเป็นผลมาทำงานในโหมด POSIX)

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


นี่คือสิ่งที่ฉันพยายามแก้ไข เราพบปัญหามากมายกับสคริปต์ที่คิดบางอย่างผิดพลาด ทำเส้นทางแบบเต็มและตั้งค่าตัวแปร env และขยะทั้งหมดจบลงด้วยเส้น cron ที่ไม่สามารถขยับได้ขนาดมหึมา
Jorge Vargas

อีกครั้งฉันขอโทษที่ฉันโตมาพร้อมกับ bash = shell ดังนั้นจึงยากที่จะจำทางเลือก (และบางครั้งก็ดีกว่า)
Jorge Vargas

1
@ Jorge: เส้นใน crontab ควรจะค่อนข้างสั้น คุณควรทำการตั้งค่าทั้งหมดที่คุณต้องการภายในสคริปต์ (หรือสคริปต์ตัวตัดคำ) นี่คือบรรทัดทั่วไปจาก crontab เป็นตัวอย่าง: 0 0 * * 1 /path/to/executable >/dev/null 2>&1จากนั้นภายใน "ปฏิบัติการ" ฉันจะตั้งค่าสำหรับ$PATHฯลฯ และใช้รายละเอียดไดเรกทอรีเต็มไปยังไฟล์อินพุตและเอาต์พุต ฯลฯ ตัวอย่างเช่น:/path/to/do_something /another/path/input_file /another/path/to/output_file
หยุดชั่วคราวจนกว่าจะมีประกาศเพิ่มเติม

1

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

การแก้ไขสคริปต์ /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

1

คำตอบที่ยอมรับจะให้วิธีเรียกใช้สคริปต์กับ 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"

0

คำตอบhttps://stackoverflow.com/a/2546509/5593430แสดงวิธีรับสภาพแวดล้อม cron และใช้กับสคริปต์ของคุณ แต่ระวังว่าสภาพแวดล้อมอาจแตกต่างกันไปขึ้นอยู่กับไฟล์ crontab ที่คุณใช้ ฉันสร้างสามรายการ cron env > logที่แตกต่างกันในการรักษาสิ่งแวดล้อมผ่าน สิ่งเหล่านี้เป็นผลลัพธ์ของ Amazon Linux 4.4.35-33.55.amzn1.x86_64

1. Global / etc / crontab พร้อมผู้ใช้รูท

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

2. ผู้ใช้ crontab ของราก ( 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

3. สคริปต์ใน /etc/cron.hourly/

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 ของคุณให้ใช้สภาพแวดล้อมที่มั่นคง


-8

ฉันไม่เชื่อว่ามี; วิธีเดียวที่ฉันรู้ว่าจะทดสอบงาน cron คือการตั้งค่าให้ทำงานหนึ่งหรือสองนาทีในอนาคตแล้วรอ


นี่คือเหตุผลที่ฉันขอจำลอง
Jorge Vargas
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.