cron ละเว้นตัวแปรที่กำหนดใน“ .bashrc” และ“ .bash_profile”


49

ฉันได้กำหนดตัวแปร "SHELL" ในไฟล์ / etc / crontab:

[martin@martin ~]$ grep SHELL /etc/crontab 
SHELL=/usr/local/bin/bash
[martin@martin ~]$ file /usr/local/bin/bash
/usr/local/bin/bash: ELF 32-bit LSB executable, Intel 80386, version 1 (FreeBSD), dynamically linked (uses shared libs), for FreeBSD 8.0 (800107), stripped
[martin@martin ~]$ 

นอกจากนี้สคริปต์ของฉันทั้งหมดในไฟล์ / etc / crontab เริ่มต้นภายใต้ผู้ใช้ "มาร์ติน" อย่างไรก็ตาม/home/martin/.bash_profile (สำหรับ login shell) และ/home/martin/.bashrc (สำหรับ non-logging shell) มีตัวแปรบางอย่างที่ถูกละเว้นในกรณีของงาน cron แต่จะใช้ในกรณีที่ฉันเข้าสู่เครื่องผ่าน SSH หรือเปิดเซสชัน bash ใหม่ ทำไม cron ไม่สนใจตัวแปรเหล่านั้น cron ไม่ใช่แค่เรียกใช้งาน "/ usr / local / bin / bash my-script.sh" ด้วยการอนุญาตสำหรับผู้ใช้ "martin" หรือไม่?


2
ผู้ใช้ Ubuntu อาจต้องการทราบว่าการเริ่มต้นของ Ubuntu .bashrcมีบรรทัดที่ห้ามไม่ให้ทำงานในเชลล์ที่ไม่มีการโต้ตอบ
joeytwiddle

คำตอบ:


72

คุณสามารถระบุไฟล์ที่คุณต้องการที่ด้านบนสุดของสคริปต์หรือเริ่มต้นงานสำหรับผู้ใช้ที่กำลังเรียกใช้งาน คำสั่ง "source" เป็นแบบในตัว คุณต้องการทำสิ่งเดียวกันหากคุณแก้ไขไฟล์เหล่านั้นเพื่อโหลดการเปลี่ยนแปลง

* * * * * source /home/user/.bash_profile; <command>

หรือ

#!/bin/bash
source /home/user/.bash_profile

<commands>

2
โปรดทราบว่า "แหล่งที่มา" อาจไม่ทำงานหาก cron ไม่ได้ใช้bashเปลือก shฉันได้เพิ่มคำตอบที่สามารถจัดการกับกรณีที่เมื่อเปลือกเป็น
Jonathan


23

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

ดูคำถามนี้: ไฟล์. bashrc คืออะไร | ผู้ใช้ขั้นสูง

และที่หนึ่งนี้:

ความแตกต่างระหว่าง. bashrc, .bash_profile และ. สิ่งแวดล้อมคืออะไร | กองล้นมากเกินไป

สคริปต์ที่แตกต่างกันทำงานขึ้นอยู่กับว่าการเชื่อมต่อเป็นเชลล์ล็อกอิน (หรือไม่) เชลล์เชิงโต้ตอบ (หรือไม่) หรือทั้งสองอย่าง

หากคุณต้องการ bashrc คุณจะต้องทำการเปลี่ยนแปลงนี้:

เมื่อ Bash เริ่มต้นแบบไม่โต้ตอบเพื่อรันเชลล์สคริปต์ตัวอย่างเช่นจะค้นหาตัวแปร BASH_ENV ในสภาพแวดล้อมขยายค่าถ้ามันปรากฏขึ้นที่นั่นและใช้ค่าที่ขยายเป็นชื่อไฟล์เพื่ออ่านและดำเนินการ . Bash จะทำงานเหมือนกับว่าคำสั่งต่อไปนี้ถูกดำเนินการ:

if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi 

แต่ค่าของตัวแปร PATH ไม่ได้ถูกใช้เพื่อค้นหาชื่อไฟล์

ตามที่ระบุไว้ข้างต้นถ้าเชลล์ที่ไม่มีการโต้ตอบถูกเรียกใช้ด้วย--loginตัวเลือก Bash จะพยายามอ่านและดำเนินการคำสั่งจากไฟล์เริ่มต้นล็อกอินของเชลล์

ที่มา: Bash Startup Files | คู่มืออ้างอิง Bash gnu.org


ดังนั้นหากเราตั้งค่า BASH_ENV ภายใน Cron สคริปต์ cash bash จะเป็นแหล่งที่มาเพราะ cron นั้นไม่ใช่แบบโต้ตอบและไม่ได้ลงชื่อเข้าใช้
CMCDragonkai

12

คุณอาจไม่สามารถเรียกใช้sourceหากshมีการใช้เชลล์ สิ่งนี้สามารถเปลี่ยนแปลงได้โดยการเพิ่มบรรทัดต่อไปนี้ใน crontab ของคุณ:

SHELL=/bin/bash
* * * * * source "/root/.bashrc"; <command>

คุณยังสามารถระบุสภาพแวดล้อม:

BASH_ENV="/root/.bashrc"
* * * * * <command>

หรือคุณสามารถใช้ท้องถิ่นของคุณ/home/user/.bashrcหากเป็นงาน cron ของผู้ใช้ (เช่นcrontab -e)

โปรดทราบว่า.bash_profileสามารถแทนที่.bashrcหากมีอยู่

เครดิต: วิธีเปลี่ยน cron shell (sh เป็น bash) ได้อย่างไร


สิ่งนี้ใช้ได้ดีสำหรับงาน Acquia Cloud Scheduled ซึ่งโดยทั่วไปจะเป็นงาน cron คุณสามารถทำเช่นเดียวกัน:SHELL=/bin/bash && source /home/YOUR_USER_NAME/.bash_profile && sh ....
Alejandro Moreno

1

สิ่งอื่นที่อาจรบกวนการจัดหาของคุณ.bashrcจาก cronjob คือการตรวจสอบใด ๆ ที่ไฟล์นี้ทำเพื่อตรวจหาเชลล์แบบโต้ตอบ

ตัวอย่างเช่นบน Ubuntu 18.04 ค่าเริ่มต้น.bashrcสำหรับผู้ใช้เริ่มต้นด้วยสิ่งนี้:

# ~/.bashrc: executed by bash(1) for non-login shells.
# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
# for examples

# If not running interactively, don't do anything
case $- in
    *i*) ;;
      *) return;;
esac

และการจัดหามันจะไม่ทำอะไรที่มีประโยชน์เพราะมันจะออกทันที


1

คุณสามารถเรียกใช้ทุบตีด้วย-lตัวเลือกเช่นนี้:

* * * * * /bin/bash -l /path/to/script arg1 arg2

-lตัวเลือกทำให้ทุบตีเข้าสู่ระบบเปลือก .bash_profileดังนั้นจึงจะอ่านของผู้ใช้ มันจะไม่อ่านของผู้ใช้เว้นแต่จะมีที่มาอย่างชัดเจนโดย.bashrc นี้เป็นเพราะเปลือกไม่โต้ตอบไม่ได้อ่านโดยอัตโนมัติ.bash_profile .bashrcแต่คุณไม่จำเป็นต้อง.bashrcใช้งาน cron เพราะ.bashrcเป็นการตั้งค่าสิ่งที่มีประโยชน์สำหรับเชลล์แบบโต้ตอบ

รูปแบบ:

หาก bash อยู่บน PATH ไม่จำเป็นต้องระบุพา ธ สัมบูรณ์:

* * * * * bash -l /path/to/script arg1 arg2

การปรับให้เหมาะสมจะเป็นการแทนที่เชลล์ปัจจุบันโดยใช้exec:

* * * * * exec bash -l /path/to/script arg1 arg2

1

bashทำหน้าที่แตกต่างกันไม่ว่าจะเป็นเชลล์หรือภาษาการเขียนโปรแกรมปกติ(เช่นperlหรือpython)

จากการออกแบบการตั้งค่าใน~/.bash_profileและ~/.bashrcอื่น ๆ มีไว้สำหรับให้ผู้ใช้ตั้งค่าสิ่งต่าง ๆ เมื่อbashเล่นบทบาทของเชลล์ (ล็อกอินเชลล์, เชลล์แทรก) นึกถึงสภาพแวดล้อมที่คุณมีในxterm(เชลล์เชิงโต้ตอบ) หรือในsshเซสชัน (ล็อกอินเชลล์) หรือในคอนโซล (เชลล์ล็อกอิน)

ในทางกลับกันbashก็เป็นภาษาการเขียนโปรแกรมที่ทรงพลัง- คิดเกี่ยวกับสคริปต์มากมายสำหรับการจัดการบริการsystemd- ซึ่งต้องใช้รูปแบบการทำงานที่แตกต่างกัน ตัวอย่างเช่นเมื่อนักพัฒนากำลังเขียนสคริปต์ของระบบหรือbashโปรแกรมเขา / เธอจะไม่ชอบที่จะแหล่งที่มาของผู้ใช้~/.bash_profileโดยอัตโนมัติ มันเป็นโปรแกรมปกติไม่ใช่เชลล์ โปรแกรมปกติ (รวมbashโปรแกรม) ธรรมชาติจะสืบทอดการตั้งค่าจาก evironement ทำงานปัจจุบัน (เปลือก) แต่ไม่ตั้งพวกเขา

ถ้าเราเขียนโปรแกรมสำหรับcronในbash-IT เพิ่งเกิดขึ้นจะเขียนในbash; ในความเป็นจริงเราสามารถเขียนในpythonหรือperlหรือ language- progamming อื่น ๆ แล้วเราจะได้มีตัวเลือกในการแหล่งbash's ~/.bash_profile(อ่าน: การตั้งค่าของเปลือกของผู้ใช้ซึ่งเพิ่งเกิดขึ้นเป็นภาษาเดียวกันของการเขียนโปรแกรมภาษาของคุณ):

[ -f /home/user/.bash_profile ] && . /home/user/.bash_profile

อย่างไรก็ตามจะเกิดอะไรขึ้นถ้าผู้ใช้นั้นไม่ได้ใช้bashเป็นเชลล์ / เธอ? เขา / เธออาจจะใช้zsh, ksh, fishฯลฯ ดังนั้นการปฏิบัติที่จะไม่ทำงานจริงๆเมื่อเขียนโปรแกรมสำหรับการใช้ที่สาธารณะ

ดังนั้นคุณสามารถแหล่งที่มา~/.bash_profileถ้าคุณคิดว่ามันจะทำงาน แต่นี่มันไม่ได้เกี่ยวกับว่าเราจะสามารถไปยังแหล่งไฟล์มันเป็นเรื่องเกี่ยวกับสิ่งที่ควรจะเป็นผลงานในระบบ: แนวคิดการออกแบบ ในระยะสั้น: เราควรจะดูbashเป็นสิ่งที่มี 2 บทบาท: เปลือกและภาษา จากนั้นทุกอย่างจะง่ายต่อการเข้าใจ


0

ฉันมีปัญหาเดียวกันเมื่อรันแอปพลิเคชันโหนดจาก cron ซึ่งใช้ NVM เพื่อที่จะทำให้ bash shell อ่านไฟล์. bashrc จาก cron เพียงแค่ประกาศคำสั่ง bash ด้วยตัวเลือกเชลล์แบบโต้ตอบ `-l

เช่น: * * * * * /bin/bash -lc '/home/user/myapp.sh restart'

หากไม่ได้ผลให้ลองตั้งค่าตัวแปรพา ธ ใน crontab

41 7 * * * /bin/bash -lc "PATH=$PATH:/home/user/.nvm/versions/node/v8.10.0/bin && /home/user/script.sh restart "

-1

วิธีจัดการกับมันคือ:

1) การใส่ตัวแปรของฉันใน (ตอนท้าย) ~/.profile:

myVarInDotProfile="someValue"

2)การสร้างสคริปต์ Bash สำหรับงาน cron ของฉัน (รายวัน) ( ~/cronDaily.sh) ที่มีคำสั่งของฉันรวมถึงการจัดหาซ้ำ~/.profle:

source ~/.profile
command ${myVarInDotProfile}/

3)การตั้งเวลาการcrontabเรียกใช้สคริปต์จากเพื่อให้ทำงานทุกวัน:

0 0 * * * bash ~/cronDaily.sh

ตัวแปรของฉันไม่ถูกเพิกเฉยและคำสั่งรันได้เป็นผลสำเร็จ


บางคนอาจพูดว่าการหาแหล่งที่มาอย่างรุนแรง~/.profileนั้นเป็นปัญหา ในกรณีเฉพาะของฉันฉันไม่เห็นว่าทำไมมันเป็นปัญหา แต่ฉันอยากจะแนะนำให้พิจารณาการสร้างไฟล์เฉพาะสำหรับสิ่งนั้น

โดยทั่วไปอาจจะมีวิธีที่ดีกว่านี้ แต่นั่นคือสิ่งที่ทำงานให้ฉันหลังจากอาการปวดมากและมันอธิบายถึงหลักการที่ว่าเป็นของทุบตี 4.3.46 crontabคุณไม่สามารถแฟ้มแหล่งที่มาจาก

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