Thêm một cái gì đó vào crontab theo chương trình (trên ssh)


13

Tôi có một tập lệnh triển khai, nó phải thêm một cái gì đó cho người dùng crontab(kích hoạt tập lệnh xóa nhật ký mỗi ngày XXX), tuy nhiên điều này chỉ phải được thực hiện trong lần triển khai đầu tiên hoặc khi cần cập nhật.

(Tôi có thể chạy xxx.py deploy envhoặc xxx.py update env)

vì vậy tôi phải làm điều này:

Check if my cronJob already exist
Put my cronJob if it does not already exist
or
update my cronjob if one of the parameter of the command is different

Tôi không thấy cách thêm / kiểm tra / xóa cái gì đó crontabmà không sử dụng crontab -ehoặc chỉnh sửa crontabtệp (tải xuống, viết lại, tải lên lại)

PS: đây là một cronjob dành riêng cho người dùng, "webadmin" sẽ làm điều đó và anh ta không nên sử dụng sudo để làm điều đó.


1
Nó có phải nằm trong một crontab dành riêng cho người dùng không? Hầu hết các công việc cron đóng gói sẵn đi vào một trong các thư mục /etc/cron.*.
một CVn

CentOS có /etc/cron.dkhông? Nếu vậy, hãy đặt tập lệnh của bạn vào đó bằng một tên duy nhất cho ứng dụng của bạn
roaima

vâng, đó là người dùng cụ thể. Tôi không thể thêm nó vào /etc/cron.d vì đó là tệp gốc, do đó, chỉ có công việc của root mới được đưa vào bên trong (tôi có thể sudo nhưng đó là một thực tiễn xấu mà tôi đã nói)
sliders_alpha

1
giống như /etc/crontab, các file trong /etc/cron.d/có trường bổ sung cho tên người dùng, ngay sau khi spec đúng tiến độ. ví dụ * * * * * username /path/to/script. Xem man 5 crontabvà tìm kiếm SYSTEM CRON.
cas

Câu trả lời:


15

ý tưởng tốt nhất của tôi cho đến nay

để kiểm tra trước xem nội dung có khớp với nội dung trong đó không và chỉ cập nhật nếu nội dung không:

if [[ $(crontab -l | egrep -v "^(#|$)" | grep -q 'some_command'; echo $?) == 1 ]]
then
    echo $(crontab -l ; echo '* 1 * * * some_command') | crontab -
fi

nhưng điều này đủ phức tạp để xây dựng một tập lệnh riêng xung quanh tác vụ cron đó.

những ý tưởng khác

bạn có thể gửi chuỗi qua stdin đến crontab (hãy cẩn thận, điều này sẽ xóa mọi mục nhập crontab trước đó):

echo "* 1 * * * some_command" | crontab -

điều này thậm chí sẽ hoạt động ngay thông qua ssh:

echo "* 1 * * * some_command" | ssh user@host "crontab -"

nếu bạn muốn nối vào tệp, bạn có thể sử dụng tệp này:

# on the machine itself
echo "$(echo '* 1 * * * some_command' ; crontab -l)" | crontab -
# via ssh
echo "$(echo '* 1 * * * some_command' ; ssh user@host crontab -l)" | ssh user@host "crontab -"

điều đó phụ thuộc: bạn có cần những gì sẽ có trong đó không? :)
Phillip -Zyan K Lee- Stockmann

awww ... không chạy bằng root? ... Tôi sẽ viết lại ...
Phillip -Zyan K Lee- Stockmann

eh, tôi thích điều đó: D
sliders_alpha

Tôi đã có hai vấn đề với giải pháp này: 1) echo '*...mở rộng *danh sách các tập tin. 2) các kết thúc dòng trong crontab đã bị xóa.
Heath Raftery

Tôi đã có thể khắc phục các sự cố này bằng cách: 1) thay đổi echo "*...và 2) xóa echo $khỏi đầu dòng.
Heath Raftery

3

Đối với hồ sơ tôi sẽ đề nghị sử dụng /etc/cron.d/. Chỉ root mới có thể ghi tệp ở đây nhưng các mục có thể được chạy như bất kỳ người dùng nào (không cần sudo).

echo '0 0 * * 0 webadmin /usr/local/bin/tidy_logfiles' > ~/webadmin.cron
scp -p ~/webadmin.cron root@remote_host:/etc/cron.d/webadmin

Điều này có thể được áp dụng nhiều lần, cập nhật webadmin.crontệp cục bộ khi cần thiết trước khi sao chép nó qua.

Bạn thậm chí có thể loại bỏ việc cung cấp:

ssh -q root@remote_host rm -f /etc/cron.d/webadmin

Lưu ý rằng trong nhiều trường hợp, bạn không thể cung cấp mật khẩu gốc của cho scp/ sshlệnh. Thay vào đó, bạn cần phải thiết lập chứng chỉ khóa công khai / riêng tư. Ngoài ra, bằng cách ngụ ý tài khoản cục bộ (bất kể đó là gì) sẽ có quyền truy cập root đầy đủ vào máy chủ từ xa. Hiện tại vẫn chưa rõ liệu đó có phải là điểm dừng cho kịch bản cụ thể của bạn hay không.


Đó là máy chủ của khách hàng của tôi, tôi không thể đăng nhập với quyền root, tôi có thể sudo vào nó NHƯNG, nếu tôi làm điều đó họ sẽ giết tôi. Đây là một công việc webadlmin vì vậy nó chỉ nên có trong công cụ webadmin, đó là những gì sysadmin nói với tôi.
sliders_alpha

@sliders_alpha công việc chỉ chạy dưới dạng webadmin. Đó là việc cung cấp đòi hỏi tương đương gốc. Tuy nhiên, tôi cũng sẽ tìm kiếm một giải pháp không root.
roaima

1
+1. /etc/cron.d/tồn tại cho chính xác mục đích này - để các gói / triển khai có thể bỏ tập tin crontab vào đây.
cas

3

Tôi thực sự khuyên bạn nên sử dụng Ansible * cho việc này thay vì tự lăn. Hoặc Puppet hoặc Chef - nhưng Ansible rất phù hợp với các kịch bản triển khai cơ sở hạ tầng bằng không như thế này.

Đó là vì có đã module có nghĩa là để giải quyết vấn đề như thế này, và các công cụ quản lý cấu hình có có idempotence là một mục tiêu thiết kế cơ sở - đó là tài sản của chỉ thay đổi khi nó cần phải ngay cả khi bạn vô tình (hay cố ý) chạy nó một lần nữa.

Đặc biệt, Ansible của cron module có thể sửa đổi crontabs người dùng. Như một phần thưởng, nếu sau này bạn muốn điều chỉnh để sử dụng crontabs hệ thống, nó sẽ là một điều chỉnh rất dễ dàng hơn là viết lại.


* từ chối trách nhiệm: Tôi làm việc cho Red Hat và Ansible là một dự án được tài trợ bởi Red Hat.


Vâng, điều này là, tôi đã không biết về ansible cách đây 2 tháng, và bây giờ chúng tôi có một kịch bản triển khai python khổng lồ (nhưng anh ấy là TẠP CHÍ, có thể đọc được, có thể bảo trì ,;)) Lần sau, tôi sẽ sử dụng trở lại là không thể (tiền tiền tiền)
sliders_alpha

1

Nếu bạn muốn thêm một công việc định kỳ thông qua tài khoản đích, hãy chạy crontab -e. Lệnh này vượt qua crontab thông qua một trình soạn thảo. Nói với nó để sử dụng một lệnh biên tập sửa đổi crontab như bạn muốn. Lệnh biên tập được thực thi dưới dạng đoạn mã shell với tên của tệp tạm thời được nối thêm.

unset VISUAL
EDITOR='update_crontab () {
  set -e
  new=$(mktemp)
  if <"$1" grep -v "^#" | grep -w do_stuff; then
    # Remove existing entries containing do_stuff
    grep -v -w do_stuff "$1" >"$new"
  else
    cp "$1" "$new"
  fi
  # Add the new entry
  echo "1 2 3 4 5 do_stuff --new-options" >>"$new"
  mv "$new" "$1"
}
update_crontab' crontab -e

Cách tiếp cận này đáng tin cậy hơn bản địa crontab -l | … | crontab -vì cách này dễ bị ảnh hưởng bởi điều kiện chủng tộc nếu crontab được chỉnh sửa đồng thời: các sửa đổi được thực hiện giữa lệnh gọi crontab -lvà lệnh gọi crontab -sẽ được hoàn tác.


1

Đây là bản phóng tác của những gì @ phillip-zyan-k-lee-stockmann đưa ra, dựa trên mã "Ý tưởng hay nhất từ ​​trước đến nay" của ông.

Những thay đổi của tôi từ (đoạn trích xuất sắc và hữu ích) của anh ấy về cơ bản là:

  • Regex cho không chỉ tên lệnh, mà cả toàn bộ mục bao gồm cả chuỗi thời gian. Bằng cách đó, nó có thể hỗ trợ thêm một lệnh ngay cả khi có các lệnh cùng tên hoặc chồng chéo trong các mục khác. (Nó vẫn sẽ không thêm cùng một lệnh trong cùng một lịch trình hai lần.)
  • Một chút đăng nhập
  • Tôi đã chuyển (và đặt tên) của tôi sang hàng giờ vì nhiều lý do; dễ dàng điều chỉnh lại theo cú pháp crontab

Và đây là mã của tôi cho những gì tôi gọi crontab-add-hourly.sh:

#!/bin/bash

# PURPOSE:
# To allow simple, programmatic addition of commands/entries into the crontab (if not already present)

cmd=$1
entry="0 * * * * $cmd"
printf "we want to add this entry:\n$entry\n\n" 
escapedEntry=$(printf '%s\n' "$entry" | sed 's:[][\/.^$*]:\\&:g') #from: https://unix.stackexchange.com/a/129063/320236
printf "but first we'll see if it's already in there using this regex pattern:\n$escapedEntry\n\n"

if [[ $(crontab -l | egrep -v '^(#|$)' | grep -q "$escapedEntry"; echo $?) == 1 ]] # from: https://unix.stackexchange.com/a/297377/320236
then
    printf "all clear; pattern was not already present; adding command to crontab hourly:\n$cmd\n\n"
    (crontab -l ; printf "$entry\n\n") | crontab -
else
    printf "pattern already present; no action taken\n\n"
fi

Ví dụ sử dụng và đầu ra:

$ ./crontab-add-hourly.sh my-script.bash

we want to add this entry:
0 * * * * my-script.bash

but first we'll see if it's already in there using this regex pattern:
0 \* \* \* \* my-script\.bash

all clear; pattern was not already present; adding command to crontab hourly:
my-script.bash

0

TL; DR: Điều này thực sự hoạt động, được thử nghiệm trong Bash 4.4.

if [[ $(crontab -l | egrep -v "^(#|$)" | grep -q 'some_command'; echo $?) == 1 ]]
then
    set -f
    printf "$(crontab -l ; echo '* * * * * some_command')\n" | crontab -
    set +f
fi

Như đã lưu ý trong các bình luận của @Phillip -Zyan K Lee- Stockmann, giải pháp đó mở rộng *vào tất cả các tệp trong thư mục hiện tại. Tôi không thể nhận được đề xuất ý kiến ​​để làm việc. set -f vô hiệu hóa việc mở rộng ký tự đại diện, xem https://stackoverflow.com/a/11456496/915441 .

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.