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 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?
Câu trả lời:
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.
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ụ
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ùngLOGNAME
đăng nhập của người dùngPATH=/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.
Một vài cách tiếp cận:
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 sh
phiên có môi trường của cron
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 . ~/.profile
trước công việc định kỳ của mình, vd
* * * * * . ~/.profile; your_command
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, dbus
v.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í nmcli
và tương tự sẽ thất bại.
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.
env - HOME="$HOME" LOGNAME="$USER" PATH="/usr/bin:/bin" SHELL="$(which sh)" command arguments
dường như để thực hiện mánh khóe
Tùy thuộc vào vỏ của tài khoản
sudo su
env -i /bin/sh
hoặc là
sudo su
env -i /bin/bash --noprofile --norc
Từ http://matthew.mceachen.us/blog/howto-simulation-the-cron-envir-1018.html
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 systemd
trê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.
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ỳ.
Đừng quên rằng vì cha mẹ của cron là init, nó chạy các chương trình mà không có thiết bị đầu cuối kiểm soát. Bạn có thể mô phỏng điều đó với một công cụ như thế này:
Theo mặc định, cron
thự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
, ksh
hoặ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ư $PATH
chính mình.
0 0 * * 1 /path/to/executable >/dev/null 2>&1
và 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
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
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"
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.
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
Quan trọng nhất PATH
, PWD
và HOME
khá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.
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.