Làm thế nào để mô phỏng cron môi trường thực thi một tập lệnh với?


253

Tôi thường có một số vấn đề với cách cron thực thi các tập lệnh vì chúng thường không có thiết lập môi trường của tôi. Có cách nào để gọi bash (?) Theo cùng cách mà cron làm để tôi có thể kiểm tra tập lệnh trước khi cài đặt chúng không?


Tôi muốn đề xuất giải pháp này: unix.stackexchange.com/questions/27289/ trên
rudi

Đưa @gregseth xa hơn một chút, tôi đã đưa ra giải pháp này: unix.stackexchange.com/questions/27289/ mẹo
Robert Brisita

Câu trả lời:


385

Thêm phần này vào crontab của bạn (tạm thời):

* * * * * env > ~/cronenv

Sau khi nó chạy, làm điều này:

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

Điều này giả định rằng cron của bạn chạy / bin / sh, là mặc định bất kể shell mặc định của người dùng.


5
lưu ý: nếu thêm nó vào toàn cầu / etc / crontab, bạn cũng sẽ cần tên người dùng. Ví dụ: * * * * * root env> ~ / cronenv
Greg

10
Tốt, ý tưởng đơn giản. Đối với người không kiên nhẫn, hãy sử dụng '* * * * *' để chạy vào phút tiếp theo và nhớ tắt lại khi bạn chơi xong ;-)
Mads Buus

5
@Madsn Để quay lại bash shell trước, hãy thử: exit
spkane

5
Tầm quan trọng của câu trả lời này không thể được đánh giá thấp. Xứng đáng với một đoạn văn trong một cuốn sách.
Xofo

1
được env - mèo ~ / cronenv` / bin / sh` nên được viết như công việc định kỳ cũng? vui lòng cho một ví dụ
JavaSa

61

Cron chỉ cung cấp môi trường này theo mặc định:

  • HOME thư mục nhà của người dùng
  • LOGNAME đăng nhập của người dùng
  • PATH=/usr/bin:/usr/sbin
  • SHELL=/usr/bin/sh

Nếu bạn cần nhiều hơn, bạn có thể tìm một tập lệnh trong đó bạn xác định môi trường của mình trước bảng lập lịch trong crontab.


7
.thường không phải là một phần của PATHnữa, vì lý do bảo mật .
l0b0

49

Một vài cách tiếp cận:

  1. Xuất cron env và nguồn nó:

    Thêm vào

    * * * * * env > ~/cronenv

    vào crontab của bạn, hãy để nó chạy một lần, tắt nó đi, sau đó chạy

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

    Và bây giờ bạn đang ở trong một shphiên có môi trường của cron

  2. Mang môi trường của bạn đến cron

    Bạn có thể bỏ qua bài tập trên và chỉ cần làm . ~/.profiletrước công việc định kỳ của mình, vd

    * * * * * . ~/.profile; your_command
  3. Sử dụng màn hình

    Hai giải pháp trên vẫn thất bại ở chỗ chúng cung cấp một môi trường được kết nối với phiên X đang chạy, với quyền truy cập, dbusv.v. Ví dụ, trên Ubuntu, nmcli(Trình quản lý mạng) sẽ hoạt động theo hai cách tiếp cận ở trên, nhưng vẫn thất bại trong cron.

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

    Thêm dòng trên vào cron, để nó chạy một lần, tắt lại. Kết nối với phiên màn hình của bạn (màn hình -r). Nếu bạn đang kiểm tra phiên màn hình đã được tạo (với ps), hãy lưu ý rằng đôi khi chúng ở thủ đô (ví dụ ps | grep SCREEN)

    Bây giờ thậm chí nmclivà tương tự sẽ thất bại.


22

Bạn có thể chạy:

env - your_command arguments

Điều này sẽ chạy your_command với môi trường trống.


4
Cron không chạy trong một môi trường hoàn toàn trống rỗng, phải không?
jldupont

2
gregseth đã xác định các biến được bao gồm trong môi trường bằng cron. Bạn có thể bao gồm các biến đó trên dòng lệnh. Lệnh $ env - PATH = "$ PATH" lập luận
DragonFax

4
@DragonFax @dimba Tôi sử dụng env - HOME="$HOME" LOGNAME="$USER" PATH="/usr/bin:/bin" SHELL="$(which sh)" command argumentsdường như để thực hiện mánh khóe
l0b0

Đây là một phương pháp đơn giản tuyệt vời để kiểm tra các tập lệnh trong môi trường "thù địch" hoặc không xác định. Nếu bạn đủ rõ ràng rằng nó sẽ chạy trong này, nó sẽ chạy theo cron.
Oli


13

Trả lời sáu năm sau: vấn đề không phù hợp với môi trường là một trong những vấn đề được giải quyết bằng systemd"bộ định thời" như là một thay thế cron. Cho dù bạn chạy "dịch vụ" systemd từ CLI hoặc qua cron, nó sẽ nhận được chính xác cùng một môi trường, tránh vấn đề không khớp với môi trường.

Vấn đề phổ biến nhất khiến các công việc cron thất bại khi chúng vượt qua thủ công là mặc định hạn chế $PATHđược đặt bởi cron, đây là vấn đề trên Ubuntu 16.04:

"/usr/bin:/bin"

Ngược lại, mặc định $PATHđược đặt systemdtrên Ubuntu 16.04 là:

"/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"

Vì vậy, đã có cơ hội tốt hơn rằng một bộ đếm thời gian systemd sẽ tìm thấy một nhị phân mà không gặp rắc rối thêm.

Nhược điểm với bộ định thời systemd, có thêm một chút thời gian để thiết lập chúng. Trước tiên, bạn tạo tệp "dịch vụ" để xác định nội dung bạn muốn chạy và tệp "hẹn giờ" để xác định lịch trình để chạy và cuối cùng "bật" bộ hẹn giờ để kích hoạt.


10

Tạo một công việc định kỳ chạy env và chuyển hướng thiết bị xuất chuẩn vào một tệp. Sử dụng tệp cùng với "env -" để tạo môi trường giống như công việc định kỳ.


Xin lỗi điều này làm tôi bối rối. "env - script" không đủ?
Jorge Vargas

Điều đó sẽ cung cấp cho bạn một môi trường trống rỗng. Khi bạn chạy tập lệnh thông qua cron, môi trường không trống.
Jens Carlberg


2

Theo mặc định, cronthực thi các công việc của nó bằng bất cứ ý tưởng nào trong hệ thống của bạn sh. Đây có thể là thực tế Bourne shell hay dash, ash, kshhoặc bash(hoặc một số khác) symlinked để sh(và như là một kết quả chạy trong chế độ POSIX).

Điều tốt nhất để làm là đảm bảo các tập lệnh của bạn có những gì họ cần và cho rằng không có gì được cung cấp cho họ. Do đó, bạn nên sử dụng thông số kỹ thuật đầy đủ của thư mục và đặt các biến môi trường như $PATHchính mình.


Đây chính xác là những gì tôi đang cố gắng giải quyết. Chúng tôi nhận được vô số vấn đề với các kịch bản giả định điều gì đó do nhầm lẫn. Thực hiện đầy đủ các đường dẫn và thiết lập các biến env và tất cả các rác kết thúc với các dòng cron khổng lồ khủng khiếp không thể nhầm lẫn
Jorge Vargas

re * sh xin lỗi tôi đã lớn lên với bash = shell nên thật khó để tôi nhớ các vỏ thay thế (và đôi khi tốt hơn).
Jorge Vargas

1
@Jorge: các dòng trong crontab nên khá ngắn. Bạn nên thực hiện tất cả các thiết lập bạn cần trong tập lệnh (hoặc tập lệnh trình bao bọc). Đây là một dòng điển hình từ một crontab làm ví dụ: 0 0 * * 1 /path/to/executable >/dev/null 2>&1và sau đó, trong "thực thi" tôi sẽ đặt giá trị cho $PATH, v.v. và sử dụng thông số kỹ thuật đầy đủ của thư mục cho các tệp đầu vào và đầu ra, v.v. Ví dụ:/path/to/do_something /another/path/input_file /another/path/to/output_file
Tạm dừng cho đến khi có thông báo mới.

1

Một cách đơn giản khác mà tôi đã tìm thấy (nhưng có thể dễ bị lỗi, tôi vẫn đang thử nghiệm) là tìm nguồn tệp hồ sơ của người dùng trước lệnh của bạn.

Chỉnh sửa tập lệnh /etc/cron.d/:

* * * * * user1 comand-that-needs-env-vars

Sẽ biến thành:

* * * * * user1 source ~/.bash_profile; source ~/.bashrc; comand-that-needs-env-vars

Dơ bẩn, nhưng nó đã hoàn thành công việc cho tôi. Có cách nào để mô phỏng đăng nhập không? Chỉ cần một lệnh bạn có thể chạy? bash --loginđã không làm việc. Có vẻ như đó sẽ là cách tốt hơn để đi.

EDIT: Đây dường như là một giải pháp vững chắc: http://www.epicserve.com/blog/2012/feb/7/my-notes-cron-directory-etccrond-ubfox-1110/

* * * * * root su --session-command="comand-that-needs-env-vars" user1 -l

1

Câu trả lời được chấp nhận sẽ đưa ra cách chạy tập lệnh với cron môi trường sẽ sử dụng. Như những người khác đã chỉ ra, đây không phải là tiêu chí cần thiết duy nhất để gỡ lỗi các công việc định kỳ.

Thật vậy, cron cũng sử dụng một thiết bị đầu cuối không tương tác, không có đầu vào kèm theo, v.v.

Nếu điều đó có ích, tôi đã viết một tập lệnh cho phép chạy lệnh / tập lệnh một cách dễ dàng vì nó sẽ được chạy bằng cron. Gọi nó với lệnh / script của bạn làm đối số đầu tiên và bạn tốt.

Kịch bản này cũng được lưu trữ (và có thể được cập nhật) trên 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

Trả lời https://stackoverflow.com/a/2546509/5593430 cho thấy cách lấy môi trường cron và sử dụng nó cho tập lệnh của bạn. Nhưng hãy lưu ý rằng môi trường có thể khác nhau tùy thuộc vào tệp crontab bạn sử dụng. Tôi đã tạo ba mục cron khác nhau để lưu môi trường thông qua env > log. Đây là các kết quả trên Amazon Linux 4.4.35-33.55.amzn1.x86_64.

1. Toàn cầu / etc / crontab với người dùng root

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. Người dùng crontab của root ( 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. Tập lệnh trong /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

Quan trọng nhất PATH, PWDHOMEkhác nhau. Đảm bảo đặt các tập lệnh này trong tập lệnh cron của bạn dựa trên môi trường ổn định.


-8

Tôi không tin là có; cách duy nhất tôi biết để kiểm tra một công việc định kỳ là thiết lập nó để chạy một hoặc hai phút trong tương lai và sau đó chờ đợi.


Đây là lý do tại sao tôi yêu cầu mô phỏng
Jorge Vargas
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.