Tại sao tập lệnh crontab không hoạt động?


525

Thông thường, crontabcác kịch bản không được thực hiện theo lịch trình hoặc như mong đợi. Có nhiều lý do cho điều đó:

  1. ký hiệu crontab sai
  2. vấn đề quyền
  3. biến môi trường

Wiki cộng đồng này nhằm mục đích tổng hợp các lý do hàng đầu cho crontabcác tập lệnh không được thực thi như mong đợi. Viết mỗi lý do trong một câu trả lời riêng biệt.

Vui lòng bao gồm một lý do cho mỗi câu trả lời - chi tiết về lý do tại sao nó không được thực thi - và sửa (các) vì lý do đó.

Vui lòng chỉ viết các vấn đề cụ thể về cron, ví dụ: các lệnh thực thi như mong đợi từ shell nhưng thực thi sai bởi cron.


12
Bạn phải đóng crontab -echo cron để có ảnh hưởng. Ví dụ, sử dụng vim tôi chỉnh sửa tệp và sử dụng :wđể ghi nó nhưng công việc không được thêm vào cron cho đến khi tôi cũng thoát. Vì vậy, tôi sẽ không nhìn thấy công việc cho đến sau khi tôi :qcũng vậy.
DutGRIFF

Tôi nghĩ cách tốt nhất để gỡ lỗi cron là kiểm tra syslog và tìm các vấn đề.
Suneel Kumar

Trong trường hợp của tôi - email sẽ chuyển đến thư mục SPAM của tôi, vì vậy ..... hãy kiểm tra xem trước khi bạn dành hàng giờ để gỡ lỗi: D
almaruf

Mất điện
Josef Klimuk 21/03/18

Câu trả lời:


501

Môi trường khác nhau

Cron vượt qua một tập hợp tối thiểu các biến môi trường cho công việc của bạn. Để thấy sự khác biệt, hãy thêm một công việc giả như thế này:

* * * * * env> /tmp/env.output

Đợi /tmp/env.outputđể được tạo, sau đó loại bỏ công việc một lần nữa. Bây giờ so sánh nội dung /tmp/env.outputvới đầu ra của envchạy trong thiết bị đầu cuối thông thường của bạn.

Một "gotcha" phổ biến ở đây là PATHbiến môi trường khác nhau. Có lẽ tập lệnh cron của bạn sử dụng lệnh somecommandđược tìm thấy /opt/someApp/bin, mà bạn đã thêm PATHvào /etc/environment? cron bỏ qua PATHtừ tập tin đó, vì vậy chạy somecommandtừ tập lệnh của bạn sẽ thất bại khi chạy với cron, nhưng hoạt động khi chạy trong một thiết bị đầu cuối. Điều đáng chú ý là các biến từ /etc/environmentsẽ được chuyển sang các công việc cron, không phải là các biến mà cron tự đặt riêng, chẳng hạn như PATH.

Để giải quyết vấn đề đó, chỉ cần đặt PATHbiến của riêng bạn ở đầu tập lệnh. Ví dụ

#!/bin/bash
PATH=/opt/someApp/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

# rest of script follows

Một số thích chỉ sử dụng đường dẫn tuyệt đối cho tất cả các lệnh thay thế. Tôi đề nghị chống lại điều đó. Xem xét những gì xảy ra nếu bạn muốn chạy tập lệnh của mình trên một hệ thống khác và trên hệ thống đó, lệnh sẽ được /opt/someAppv2.2/binthay thế. Bạn sẽ phải đi qua toàn bộ kịch bản thay thế /opt/someApp/binvới /opt/someAppv2.2/binthay vì chỉ làm một chỉnh sửa nhỏ trên dòng đầu tiên của kịch bản.

Bạn cũng có thể đặt biến PATH trong tệp crontab, sẽ áp dụng cho tất cả các công việc định kỳ. Ví dụ

PATH=/opt/someApp/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

15 1 * * * backupscript --incremental /home /root

5
Tôi nghĩ rằng tôi đã rơi vào điều này, và dòng mới cuối cùng ... gấp đôi whammy.
WernerCD

6
+1 vì env, tôi đã hoàn toàn quên mất lệnh đó và nghĩ rằng PATH đang hoạt động. Nó thực sự rất khác biệt trong trường hợp của tôi.
Izkata

8
@pbr Nếu các thư mục như vậy có thể ghi được cho người khác, hệ thống đã bị xâm phạm.
geirha

6
@pbr Một sysadmin có thể vô tình xóa hệ thống tập tin gốc. Bạn không thể bảo vệ chống lại các sysadins phạm sai lầm ngớ ngẩn. Nếu bạn cài đặt phiên bản mới hơn của trình thông dịch không tương thích ngược, tôi sẽ không muốn bị hỏng. Cách lành mạnh để xử lý đó là cài đặt nó như một lệnh khác. Ví dụ: bạn có python phiên bản 2.x và cài đặt python 3, bạn cài đặt nó là python3, không phải python. Và như đối với / opt / someApp / bin, tại sao trên trái đất nó sẽ không có quyền / quyền sở hữu lành mạnh? bất kỳ quản trị viên lành mạnh nào cũng sẽ đảm bảo quyền / quyền sở hữu lành mạnh trên các tệp hệ thống.
geirha

2
@pbr Có vẻ như chúng ta có thể đi mãi mãi, vâng. Tôi vẫn không thấy lý do tại sao đó là một ý tưởng tồi để sử dụng PATH. Nếu bạn muốn thảo luận thêm về vấn đề này trong một phương tiện phù hợp hơn để thảo luận, bạn sẽ tìm thấy tôi trong #ubfox và #bash, trong số các kênh khác, trên irc.freenode.net
geirha

336

Gotcha hàng đầu của tôi: Nếu bạn quên thêm một dòng mới vào cuối crontabtập tin. Nói cách khác, tệp crontab nên kết thúc bằng một dòng trống.

Dưới đây là phần có liên quan trong các trang hướng dẫn cho vấn đề này ( man crontabsau đó bỏ qua đến cuối):

   Although cron requires that each entry in a crontab end  in  a  newline
   character,  neither the crontab command nor the cron daemon will detect
   this error. Instead, the crontab will appear to load normally. However,
   the  command  will  never  run.  The best choice is to ensure that your
   crontab has a blank line at the end.

   4th Berkeley Distribution      29 December 1993               CRONTAB(1)

91
Đây là một showstopper như vậy, tại sao nó không được sửa chữa trong nhiều năm qua?
Capi Etheriel

2
Có vẻ như đã được sửa trong cron Vixie: man crontabtrên Ubuntu 10.10 nói rằng "cron yêu cầu mỗi mục trong crontab kết thúc bằng một ký tự dòng mới. Nếu mục cuối trong crontab bị thiếu dòng mới, cron sẽ xem xét crontab (ít nhất là một phần) và từ chối cài đặt nó. " (Và ngày kết thúc là ngày 19 tháng 4 năm 2010)
Marius Gedminas

19
@barraponto Đây thực sự là một lỗi trong trình soạn thảo văn bản mới. Ký tự "dòng mới" được coi là ký tự kết thúc dòng , vì vậy dòng cuối cùng trong tệp văn bản được cho là kết thúc bằng ký tự dòng mới không được hiển thị trong trình chỉnh sửa. Vi và vim sử dụng đúng ký tự và cron được tạo trước khi các biên tập viên mới bắt đầu hành vi kỳ quặc của họ ... Do đó, chơi nó lưu và bao gồm một dòng trống.
Izkata

6
Nếu bạn chỉnh sửa crontab bằng cách sử dụng crontab -enó sẽ kiểm tra cú pháp của tệp trước khi cho phép lưu, bao gồm kiểm tra dòng mới.
Tom Harrison Jr

2
@ Chan-HoSuh, theo trang man "cron yêu cầu mỗi mục trong crontab kết thúc bằng một ký tự dòng mới. Nếu mục cuối cùng trong crontab bị thiếu dòng mới, cron sẽ xem xét crontab (ít nhất là một phần) bị hỏng và từ chối cài đặt nó." Hành vi này sẽ được gọi khi chỉnh sửa sau đó lưu crontab bằng -etùy chọn và độc lập với trình chỉnh sửa .
Tom Harrison Jr

139

Cron daemon không chạy. Tôi thực sự thất vọng với điều này vài tháng trước.

Thể loại:

pgrep cron 

Nếu bạn thấy không có số, thì cron không chạy. sudo /etc/init.d/cron startcó thể được sử dụng để bắt đầu cron.

EDIT: Thay vì gọi các script init thông qua /etc/init.d, hãy sử dụng tiện ích dịch vụ, vd

sudo service cron start

EDIT: Ngoài ra, bạn có thể sử dụng systemctl trong Linux hiện đại, vd

sudo systemctl start cron

47
Cảm ơn đã chỉ cho tôi pgrep. Tôi tiếp tục làm ps -ef | grep foo
ripper234 17/03/2016

4
Bạn cũng có thể sử dụng pidof cronsẽ bỏ qua kết quả cho các ứng dụng khác cũng có từ 'cron', như crontab.
Pithikos

Thật kỳ lạ, tất cả những thứ này cho tôi không có gì để hiển thị cron đang chạy, nhưng nếu tôi chạy sudo service cron starttôi nhận đượcstart: Job is already running: cron
Colleen

1
service crond startnếu centos của nó / RHEL
Srihari Karanth

91

Các kịch bản tên tập tin trong cron.d/, cron.daily/, cron.hourly/, vv, nên không chứa dấu chấm ( .), nếu không chạy phần sẽ bỏ qua chúng.

Xem phần chạy (8):

   If neither the --lsbsysinit option nor the --regex option is given then
   the names must consist entirely of upper and lower case  letters,  dig‐
   its, underscores, and hyphens.

   If  the  --lsbsysinit  option  is given, then the names must not end in
   .dpkg-old  or .dpkg-dist or .dpkg-new or .dpkg-tmp, and must belong  to
   one  or more of the following namespaces: the LANANA-assigned namespace
   (^[a-z0-9]+$);   the   LSB   hierarchical   and   reserved   namespaces
   (^_?([a-z0-9_.]+-)+[a-z0-9]+$);  and  the  Debian cron script namespace
   (^[a-zA-Z0-9_-]+$).

Vì vậy, nếu bạn có tập lệnh cron backup.sh, analyze-logs.pltrong cron.daily/thư mục, tốt nhất bạn nên xóa tên tiện ích mở rộng.


10
Đây là một tính năng không phải là một lỗi - nó giữ cho mọi thứ như myscript.backup hoặc myscript.origen hoặc myscript.rpm-new chạy ngay bên cạnh myscript.
pbr

@pbr: có ý nghĩa Ít nhất nó sẽ hữu ích cho việc gỡ lỗi nếu run-parts --test(hoặc một tùy chọn tưởng tượng khác như --debugxuất ra các tệp mà nó bỏ qua bao gồm cả lý do.
Rabarberski

8
Nếu đây là một tính năng, nó không phải là một tính năng hay :( Rất nhiều người sử dụng dấu chấm trong tên tệp (backup.sh là một tính năng phổ biến nhất). Nếu bạn muốn một tập lệnh dừng thực thi, phương thức hợp lý nhất sẽ là xóa nó khỏi thư mục "cron.d".
MatuDuke

7
Đây là một tính năng xấu đến nỗi nó thực sự là một lỗi. Đó là thực tế phổ biến để yêu cầu một kết thúc cụ thể (như ".list" hoặc ".cron" hoặc một cái gì đó) nếu mọi người muốn đảm bảo rằng mọi thứ chỉ được chạy khi có ý định. Tự ý chọn dấu chấm làm dấu phân tách có khả năng cho ".bak" hoặc ".temp" hoặc bất cứ điều gì, là hoàn toàn không thể đoán trước ngoại trừ theo cách mà nó có thể dự đoán sẽ khiến mọi người nhầm lẫn. Các kết thúc hợp pháp như ".sh" và ".pl" đã được sử dụng rộng rãi trong nhiều thập kỷ. Tuy nhiên, nhiều người sử dụng "_bak" hoặc "_temp" hoặc "-bak" thay vì dấu chấm. Đây là một sự lựa chọn thiết kế khủng khiếp; đó là một lỗi thiết kế tốt nhất.
Teekin

68

Trong nhiều môi trường, cron thực thi các lệnh bằng cách sử dụng sh, trong khi nhiều người cho rằng nó sẽ sử dụng bash.

Đề xuất kiểm tra hoặc sửa lỗi này cho lệnh không thành công:

  • Hãy thử chạy lệnh shđể xem nó có hoạt động không:

    sh -c "mycommand"
    
  • Gói lệnh trong một bash subshell để đảm bảo nó được chạy trong bash:

    bash -c "mybashcommand"
    
  • Yêu cầu cron chạy tất cả các lệnh trong bash bằng cách đặt shell ở đầu crontab của bạn:

    SHELL=/bin/bash
    
  • Nếu lệnh là tập lệnh, hãy đảm bảo tập lệnh chứa shebang:

    #!/bin/bash
    

đề nghị bash là rất hữu ích, vấn đề cố định với cron của tôi.
Maxim Galushka

Điều này chỉ gây ra cho tôi 1 giờ lo lắng / xử lý sự cố. Thậm chí nhiều rắc rối hơn nếu bạn không nhận thức được vấn đề là tập lệnh sẽ chạy thủ công chỉ tốt nếu bạn là trình bao điển hình bash, nhưng không phải với cron. Cảm ơn!
Hendy

Một thời gian dài trước đây tôi gặp phải một điều gì đó liên quan: Lệnh sourceđang trong bash nhưng không phải sh. Trong cron / sh, sử dụng dấu chấm: . envfilethay vì source envfile.
kungphu

@Clockwork sh "mycommand"bảo shchạy mycommand dưới dạng tệp script. Ý bạn là sh -c "mycommand"sao Ở mức độ nào, câu trả lời này dường như là về việc làm cho lệnh chạy trong bash một cách cụ thể, vậy tại sao bạn lại thêm lệnh cho shđây?
Olorin

@Olorin Theo hiểu biết của tôi, mục tiêu của điểm đầu tiên là thử và chạy nó với sh, để xem vấn đề có thực sự đến từ thực tế là cron đang chạy nó với sh thay vì bash. Sau đó, một lần nữa, tôi có ít kiến ​​thức về vấn đề này, vì vậy tôi có thể sai.
Đồng hồ

40

Tôi đã có một số vấn đề với các múi giờ. Cron đã chạy với múi giờ cài đặt mới. Giải pháp là khởi động lại cron:

sudo service cron restart

6
Có, sau khi thay đổi múi giờ trên một hệ thống, người ta phải khởi động lại mọi dịch vụ quan tâm đến thời gian đó hoặc khởi động lại. Tôi thích khởi động lại, để chắc chắn rằng tôi đã nắm bắt được mọi thứ.
pbr

Ôi vì Chúa, đã giết hàng giờ vì điều này. Đã thử khởi động lại dịch vụ sau khi * * * * * touch /tmp/cronworkskhông làm gì, nhưng vẫn có RELOADtại cronlog.
Ấn Độ

36

Đường dẫn tuyệt đối nên được sử dụng cho các tập lệnh:

Ví dụ: /bin/grepnên được sử dụng thay vì grep:

# m h  dom mon dow   command
0 0 *  *  *  /bin/grep ERROR /home/adam/run.log &> /tmp/errors

Thay vì:

# m h  dom mon dow   command
0 0 *  *  *  grep ERROR /home/adam/run.log &> /tmp/errors

Điều này đặc biệt khó khăn, bởi vì cùng một lệnh sẽ hoạt động khi được thực thi từ shell. Lý do là cronkhông có PATHbiến môi trường giống như người dùng.


3
xem câu trả lời của geirha, bạn có thể (phải) xác định Pron của cron
Capi Etheriel

9
Bzzt. bạn KHÔNG cần phải xác định ĐƯỜNG - sử dụng các đường dẫn tuyệt đối là cách thực hành tốt nhất ở đây. "bởi vì một thực thi có thể ở đâu đó trên một số máy tính khác", không trump "Tôi muốn nó chạy chính xác chương trình này và không một ai có người khác được đắp vào con đường trước mặt của chương trình ban đầu của tôi"
PBR

1
vâng đây là nó cho tôi, bên ngoài cron tôi có thể chạy lệnh trực tiếp, bên trong cron nó cần /usr/bin/whateverđường dẫn đầy đủ
Anentropic

32

Nếu lệnh crontab của bạn có %ký hiệu trong đó, cron sẽ cố gắng giải thích nó. Vì vậy, nếu bạn đang sử dụng bất kỳ lệnh nào có %trong đó (chẳng hạn như đặc tả định dạng cho lệnh date), bạn sẽ cần phải thoát nó.

Điều đó và các vấn đề tốt khác ở đây:
http://www.pantz.org/software/cron/croninfo.html


Đây là những gì đã khiến công việc Cron của tôi thất bại trong tuần qua. Cuối cùng đã tìm ra rằng Ngày của tôi không có ký tự thoát (dấu gạch chéo ngược cho bất kỳ người nào khác đang tìm kiếm ký tự thoát là gì). Yay!
Valien


25

Cron đang gọi một kịch bản không thể thực thi được.

Bằng cách chạy chmod +x /path/to/scriptập lệnh trở nên thực thi và sẽ giải quyết vấn đề này.


5
Điều đó không phải là duy nhất cronvà dễ dàng theo dõi bằng cách đơn giản là cố gắng thực thi /path/to/scripttừ dòng lệnh.
Adam Matan

4
Nếu bạn đã quen với việc thực thi các tập lệnh bằng . scriptnamehoặc sh scriptnamehoặc bash scriptname, thì điều này sẽ trở thành một cronvấn đề cụ thể.
Eliah Kagan

24

Cũng có thể mật khẩu của người dùng đã hết hạn. Ngay cả mật khẩu của root cũng có thể hết hạn. Bạn có thể tail -f /var/log/cron.logvà bạn sẽ thấy cron thất bại với mật khẩu đã hết hạn. Bạn có thể đặt mật khẩu không bao giờ hết hạn bằng cách thực hiện việc này:passwd -x -1 <username>

Trong một số hệ thống (Debian, Ubuntu), việc đăng nhập cron không được bật theo mặc định. Trong /etc/rsyslog.conf hoặc /etc/rsyslog.d/50-default.conf dòng:

# cron.*                          /var/log/cron.log

nên được chỉnh sửa ( sudo nano /etc/rsyslog.conf) không ghi chú vào:

cron.*                          /var/log/cron.log

Sau đó, bạn cần khởi động lại rsyslog qua

/etc/init.d/rsyslog restart

hoặc là

service rsyslog restart 

Nguồn: Cho phép đăng nhập crontab trong Debian Linux

Trong một số hệ thống (Ubuntu) tệp ghi nhật ký riêng cho cron không được bật theo mặc định, nhưng các nhật ký liên quan đến cron sẽ xuất hiện trong tệp syslog. Người ta có thể sử dụng

cat /var/log/syslog | grep cron -i

để xem các tin nhắn liên quan đến cron.


Tôi có Debian (wheezy) nhưng không có /etc/init.d/rsyslog, chỉ có inetutils-syslogd và sysklogd. Tôi có phải cài đặt một cái gì đó hay chỉ cần khởi động lại một trong hai?
hgoebl

18

Nếu cronjob của bạn gọi các ứng dụng GUI, bạn cần cho họ biết họ nên sử dụng loại HIỂN THỊ nào.

Ví dụ: Firefox khởi chạy với cron.

Kịch bản của bạn nên chứa export DISPLAY=:0một nơi nào đó.


aplay cần cái này vì một số lý do. cảm ơn bạn
IljaBek

* * * * * export DISPLAY=:0 && <command>
LoMaPh

15

Vấn đề về quyền là khá phổ biến, tôi sợ.

Lưu ý rằng một cách giải quyết chung là thực thi mọi thứ bằng crontab của root, đôi khi đó là một ý tưởng thực sự tồi tệ. Đặt quyền thích hợp chắc chắn là một vấn đề bị bỏ qua phần lớn.


Lưu ý rằng nếu bạn có một dòng crontab được đặt thành đầu ra ống thành một tệp chưa tồn tại và thư mục của tệp là một dòng mà người dùng cron không có quyền truy cập, thì dòng đó sẽ không thực thi.
Evan Donovan

14

Không cho phép bảng cron

Một bảng cron bị từ chối nếu sự cho phép của nó không an toàn

sudo service cron restart
grep -i cron /var/log/syslog|tail -2
2013-02-05T03:47:49.283841+01:00 ubuntu cron[49906]: (user) INSECURE MODE (mode 0600 expected) (crontabs/user)

Vấn đề được giải quyết với

# correct permission
sudo chmod 600 /var/spool/cron/crontabs/user
# signal crond to reload the file
sudo touch /var/spool/cron/crontabs

Đầu tiên tôi tự tìm ra nó và sau đó tôi tìm thấy câu trả lời của bạn! Vẫn cảm ơn rất nhiều! Trong trường hợp của tôi, tôi đã hoàn nguyên / khôi phục một số crontabs trong / var / spool / cron / crontabs thông qua SVN đã thay đổi quyền của nó!
alfonx

12

Script là vị trí nhạy cảm. Điều này có liên quan đến việc luôn sử dụng các đường dẫn tuyệt đối trong một tập lệnh, nhưng không hoàn toàn giống nhau. Công việc định kỳ của bạn có thể cần đến cdmột thư mục cụ thể trước khi chạy, ví dụ: tác vụ cào trên ứng dụng Rails có thể cần phải nằm trong ứng dụng gốc cho Rake để tìm nhiệm vụ chính xác, chưa kể đến cấu hình cơ sở dữ liệu phù hợp, v.v.

Vì vậy, một mục crontab của

23 3 * * * /usr/bin/rake db:session_purge RAILS_ENV=production

sẽ tốt hơn

23 3 * * * cd / var / www / sản xuất / hiện tại && / usr / bin / rake db: session_purge RAILS_ENV = sản xuất

Hoặc, để giữ cho mục nhập crontab đơn giản hơn và ít giòn hơn:

23 3 * * * /home/<user>/scripts/session-purge.sh

với đoạn mã sau /home/<user>/scripts/session-purge.sh:

cd / var / www / sản xuất / hiện tại
/ usr / bin / rake db: session_purge RAILS_ENV = sản xuất

1
Nếu tập lệnh được gọi từ cron được viết bằng ngôn ngữ được dịch như PHP, bạn có thể cần phải đặt thư mục làm việc trong chính tập lệnh. Ví dụ: trong PHP: chdir(dirname(__FILE__));
Evan Donovan

Chỉ bị bắt với cái này: tập lệnh đã từng nằm trong thư mục gốc của tôi, nhưng sau đó tôi đã di chuyển nó (và cập nhật crontab) và không thể hiểu tại sao nó không hoạt động. Hóa ra tập lệnh đang sử dụng một đường dẫn tương đối, giả sử rằng nó có liên quan đến vị trí của tập lệnh nhưng thực tế nó liên quan đến thư mục gốc của thư mục nhà tôi vì đó là thư mục làm việc mà cron đang sử dụng, đó là lý do tại sao tập lệnh làm việc khi nó được trong thư mục gốc của thư mục chính của tôi (vì thư mục làm việc dự kiến của kịch bản và nó thực sự làm việc chỉ xảy ra trùng).
Micheal Johnson

11

Thông số kỹ thuật Crontab hoạt động trong quá khứ có thể bị hỏng khi được chuyển từ tệp crontab này sang tệp khác. Đôi khi, lý do là bạn đã chuyển thông số kỹ thuật từ tệp crontab hệ thống sang tệp crontab của người dùng hoặc ngược lại.

Định dạng đặc tả công việc cron khác nhau giữa các tệp crontab của người dùng (/ var / spool / cron / username hoặc / var / spool / cron / crontabs / username) và crontabs của hệ thống ( /etc/crontabvà các tệp trong /etc/cron.d).

Các crontabs hệ thống có thêm một trường 'người dùng' ngay trước khi lệnh chạy.

Điều này sẽ gây ra lỗi khi nêu những điều như george; command not foundkhi bạn di chuyển lệnh ra khỏi /etc/crontabhoặc một tệp /etc/cron.dvào tệp crontab của người dùng.

Ngược lại, cron sẽ cung cấp các lỗi giống /usr/bin/restartxyz is not a valid usernamehoặc tương tự khi điều ngược lại xảy ra.


10

kịch bản cron đang gọi một lệnh với tùy chọn --verbose

Tôi đã có một kịch bản cron thất bại đối với tôi vì tôi đang ở chế độ lái tự động trong khi gõ tập lệnh và tôi đã bao gồm tùy chọn --verbose:

#!/bin/bash
some commands
tar cvfz /my/archive/file.tar.gz /my/shared/directory
come more commands

Kịch bản chạy tốt khi thực thi từ shell, nhưng không thành công khi chạy từ crontab vì đầu ra dài dòng sẽ chuyển sang stdout khi chạy từ shell, nhưng không xuất hiện khi chạy từ crontab. Dễ dàng sửa chữa để loại bỏ 'v':

#!/bin/bash
some commands
tar cfz /my/archive/file.tar.gz /my/shared/directory
some more commands

5
Tại sao điều này gây ra một thất bại? Vấn đề đệm?
Adam Matan

Bất kỳ kết quả đầu ra hoặc lỗi nào được xử lý thông qua các công việc định kỳ đều được gửi đến hộp thư của bạn. Vì vậy, chúng tôi không bao giờ quên quan tâm đến các lỗi / đầu ra này. Chúng tôi có thể chuyển hướng chúng đến bất kỳ tệp nào hoặc / dev / null
Nischay

10

Lý do thường xuyên nhất tôi thấy cron thất bại trong một lịch trình được nêu không chính xác. Cần thực hành để chỉ định một công việc được lên lịch vào lúc 11:15 15 23 * * *thay vì * * 11 15 *hoặc 11 15 * * *. Ngày trong tuần cho công việc sau nửa đêm cũng bị nhầm lẫn MF là 2-6sau nửa đêm, không 1-5. Ngày cụ thể thường là một vấn đề vì chúng tôi hiếm khi sử dụng chúng * * 3 1 *không phải là ngày 3 tháng 3. Nếu bạn không chắc chắn, hãy kiểm tra lịch trình cron của bạn trực tuyến tại https://crontab.guru/ .

Nếu công việc của bạn với các nền tảng khác nhau sử dụng các tùy chọn không được hỗ trợ như 2/3thông số kỹ thuật về thời gian cũng có thể gây ra lỗi. Đây là một tùy chọn rất hữu ích nhưng không phổ biến. Tôi cũng đã chạy qua các vấn đề với danh sách như 1-5hoặc 1,3,5.

Sử dụng các đường dẫn không đủ tiêu chuẩn cũng đã gây ra vấn đề. Đường dẫn mặc định thường là /bin:/usr/binnhư vậy chỉ các lệnh tiêu chuẩn sẽ chạy. Những thư mục này thường không có lệnh mong muốn. Điều này cũng ảnh hưởng đến các tập lệnh sử dụng các lệnh không chuẩn. Các biến môi trường khác cũng có thể bị thiếu.

Đóng băng một crontab hiện có hoàn toàn đã gây ra cho tôi các vấn đề. Bây giờ tôi tải từ một bản sao tập tin. Điều này có thể được phục hồi từ crontab hiện tại bằng cách sử dụng crontab -lnếu nó bị ghi đè. Tôi giữ bản sao của crontab trong ~ / bin. Nó được bình luận trong suốt và kết thúc với dòng # EOF. Điều này được tải lại hàng ngày từ một mục crontab như:

#! / usr / bin / crontab
# Tải lại crontab này
#
54 12 * * * $ {HOME} / thùng / crontab

Lệnh tải lại ở trên phụ thuộc vào một crontab thực thi với một đường dẫn bang chạy crontab. Một số hệ thống yêu cầu crontab đang chạy trong lệnh và chỉ định tệp. Nếu thư mục được chia sẻ mạng, thì tôi thường sử dụng crontab.$(hostname)làm tên của tệp. Điều này cuối cùng sẽ sửa các trường hợp trong đó crontab sai được tải trên máy chủ sai.

Việc sử dụng tệp cung cấp một bản sao lưu của crontab nên là gì và cho phép các chỉnh sửa tạm thời (lần duy nhất tôi sử dụng crontab -e) được sao lưu tự động. Có các tiêu đề có sẵn giúp nhận được các tham số lập lịch đúng. Tôi đã thêm chúng khi người dùng thiếu kinh nghiệm sẽ chỉnh sửa crontab.

Hiếm khi, tôi đã chạy vào các lệnh yêu cầu đầu vào của người dùng. Những thất bại trong crontab, mặc dù một số sẽ hoạt động với chuyển hướng đầu vào.


3
Điều này bao gồm ba vấn đề riêng biệt. Họ có thể được chia thành các câu trả lời riêng biệt?
Eliah Kagan

9
Bạn có thể giải thích làm thế nào 30 23 * * * để dịch sang 11:15 PM?
JYelton

@JYelton Điều đó rõ ràng là sai, nó nên được 15 23 * * *. Sửa chữa ngay.
Melebius

7

Nếu bạn đang truy cập tài khoản qua các khóa SSH, có thể đăng nhập vào tài khoản nhưng không nhận thấy rằng mật khẩu trên tài khoản đã bị khóa (ví dụ: do hết hạn mật khẩu hoặc không hợp lệ)

Nếu hệ thống đang sử dụng PAM và tài khoản bị khóa, điều này có thể ngăn cronjob của nó chạy. (Tôi đã thử nghiệm điều này trên Solaris, nhưng không phải trên Ubuntu)

Bạn có thể tìm thấy những tin nhắn như thế này trong / var / adm / message:

24 tháng 10 07:51:00 mybox cron [29024]: [ID 731128 auth.notice] pam_unix_account: cron đang cố xác thực tài khoản myuser bị khóa từ máy chủ cục bộ
Ngày 24 tháng 10 07:51:00 mybox cron [29063]: [ID 731128 auth.notice] pam_unix_account: cron đang cố xác thực tài khoản myuser bị khóa từ máy chủ cục bộ
24 tháng 10 07:53:00 mybox cron [29098]: [ID 731128 auth.notice] pam_unix_account: cron đang cố xác thực tài khoản myuser bị khóa từ máy chủ cục bộ
24 tháng 10 07:54:00 mybox cron [29527]: [ID 731128 auth.notice] pam_unix_account: cron đang cố xác thực tài khoản myuser bị khóa từ máy chủ cục bộ

Tất cả bạn cần làm là chạy:

# passwd -u <USERNAME>

là root để mở khóa tài khoản và crontab sẽ hoạt động trở lại.


7

Nếu bạn có một lệnh như thế này:

* * * * * /path/to/script >> /tmp/output

và nó không hoạt động và bạn không thể thấy bất kỳ đầu ra nào, điều đó có thể không nhất thiết có nghĩa là cron không hoạt động. Kịch bản có thể bị phá vỡ và đầu ra sẽ chuyển sang thiết bị lỗi chuẩn không được chuyển đến / tmp / đầu ra. Kiểm tra xem đây không phải là trường hợp, bằng cách nắm bắt đầu ra này:

* * * * * /path/to/script >> /tmp/output 2>&1

để xem nếu điều này giúp bạn nắm bắt vấn đề của bạn.


3

=== Cảnh báo Docker ===

Nếu bạn đang sử dụng docker,

Tôi nghĩ thật phù hợp khi thêm rằng tôi không thể quản lý để tạo cron chạy trong nền.

Để chạy một công việc định kỳ bên trong container, tôi đã sử dụng trình giám sát và chạy cron -fcùng với quy trình khác.

Chỉnh sửa: Một vấn đề khác - Tôi cũng không quản lý để nó hoạt động khi chạy container với mạng HOST. Cũng xem vấn đề này tại đây: https://github.com/phusion/baseimage-docker/issues/144



3

Tôi đã viết một tập lệnh shell cài đặt để tạo một tập lệnh khác để xóa dữ liệu giao dịch cũ khỏi cơ sở dữ liệu. Là một phần của nhiệm vụ, nó phải cấu hình croncông việc hàng ngày để chạy vào thời gian tùy ý, khi tải cơ sở dữ liệu thấp.

Tôi đã tạo một tập tin mycronjobvới lịch trình cron, tên người dùng và lệnh và sao chép nó vào /etc/cron.dthư mục. Hai gotchas của tôi:

  1. mycronjob tập tin phải được sở hữu bởi root để chạy
  2. Tôi đã phải đặt quyền của tệp thành 644 - 664 sẽ không chạy.

Một vấn đề về quyền sẽ xuất hiện /var/log/syslogdưới dạng tương tự:

Apr 24 18:30:01 ip-11-22-33-44 cron[40980]: (*system*) INSECURE MODE (group/other writable) (/etc/crontab)
Apr 24 18:30:01 ip-11-22-33-44 cron[40980]: (*system*) INSECURE MODE (group/other writable) (/etc/cron.d/user)

Dòng đầu tiên đề cập đến /etc/crontabtệp và sau đó là tệp tôi đặt bên dưới /etc/cront.d.


2

Dòng viết theo cách crontab không hiểu. Nó cần phải được viết chính xác. Đây là CrontabHowTo .


1
Làm thế nào điều này có thể được gỡ lỗi?
Adam Matan

Xem lại nhật ký lỗi của cron là cách phổ biến nhất. IIRC 'crontab -e' thực hiện phân tích cú pháp sau khi bạn đã chỉnh sửa tệp - nhưng điều đó có thể không phổ biến.
pbr

2

Cron daemon có thể đang chạy, nhưng không thực sự hoạt động. Hãy thử khởi động lại cron:

sudo /etc/init.d/cron restart

3
Tôi KHÔNG BAO GIỜ thấy trường hợp này trong sản xuất. Điều đó không có nghĩa là nó đã không xảy ra - chỉ là tôi đã không thấy nó trong 30 năm qua tôi đã sử dụng UNIX và Linux. Cron là cực kỳ mạnh mẽ.
pbr

1
Tôi không chắc nhưng tôi nghĩ điều này thực sự đã xảy ra với tôi. Tôi đã thử pidofcron và không có gì. Đã thử sử dụng servicetiện ích và nó cho biết cron đã chạy. Chỉ cần chạy lệnh này và chạy pidoflại và tôi nhận được một kết quả.
Colleen

2

Viết thư cho cron qua "crontab -e" với đối số tên người dùng trong một dòng. Tôi đã thấy các ví dụ về người dùng (hoặc sysadins) viết các tập lệnh shell của họ và không hiểu tại sao họ không tự động hóa. Đối số "người dùng" tồn tại trong / etc / crontab, nhưng không phải là tệp do người dùng xác định. vì vậy, ví dụ, tệp cá nhân của bạn sẽ giống như:

# m h dom mon dow command

* * */2  *   *  /some/shell/script

trong khi đó / etc / crontab sẽ là:

# m h dom mon dow user   command

* * */2  *   *  jdoe   /some/shell/script

Vì vậy, tại sao bạn sẽ làm sau? Chà, tùy thuộc vào cách bạn muốn đặt quyền của mình, điều này có thể trở nên rất phức tạp. Tôi đã viết các kịch bản để tự động hóa các tác vụ cho những người dùng không hiểu những điều phức tạp hoặc không muốn bận tâm đến sự vất vả này. Bằng cách đặt quyền --x------, tôi có thể làm cho tập lệnh có thể thực thi được mà không thể đọc được (và có thể vô tình thay đổi). Tuy nhiên, tôi có thể muốn chạy lệnh này với một số lệnh khác từ một tệp (do đó giúp duy trì dễ dàng hơn) nhưng đảm bảo đầu ra tệp được gán đúng chủ sở hữu. Làm như vậy (ít nhất là trong Ubuntu 10.10) phá vỡ cả khả năng không thể đọc tệp cũng như thực thi, cộng với vấn đề được đề cập ở trên với việc đặt dấu chấm vào / etc / crontab (đủ vui, không gây ra lỗi khi đi qua crontab -e) .

Ví dụ, tôi đã thấy các phiên bản sudo crontab -eđược sử dụng để chạy tập lệnh có quyền root, với chown username file_outputtập lệnh shell tương ứng . Sloppy, nhưng nó hoạt động. IMHO, Tùy chọn duyên dáng hơn là đặt nó /etc/crontabvới tên người dùng được khai báo và quyền thích hợp, do đó, file_outputđi đến đúng nơi và chủ sở hữu.


"Làm như vậy (ít nhất là trong Ubuntu 10.10) phá vỡ cả khả năng không thể đọc tệp cũng như thực thi ....." Tôi nên làm rõ: / etc / crontab (theo mặc định) yêu cầu quyền đọc và thực thi, trong khi bạn COULD chạy "sudo crontab -e" để tạo một cronjob ghi đè cả nhu cầu cho phép "w" và vấn đề với các tiện ích mở rộng như ".sh". Tôi đã không có thời gian để tách mã cron và kiểm tra lý do tại sao nó hoạt động, chỉ là một chi tiết tôi nhận thấy.
Mange

2

Xây dựng những gì Aaron Peart đã đề cập về chế độ dài dòng, đôi khi các tập lệnh không ở chế độ dài dòng sẽ khởi tạo nhưng không kết thúc nếu hành vi mặc định của lệnh được bao gồm là xuất một dòng hoặc nhiều hơn tới màn hình khi khởi động. Ví dụ: tôi đã viết một tập lệnh sao lưu cho mạng nội bộ của chúng tôi sử dụng curl, một tiện ích tải xuống hoặc tải tệp lên máy chủ từ xa và khá tiện dụng nếu bạn chỉ có thể truy cập các tệp từ xa thông qua HTTP. Sử dụng 'curl http: //s Something.com/somefile.xls ' đã khiến tập lệnh tôi viết bị treo và không bao giờ hoàn thành vì nó tạo ra một dòng mới theo sau là một dòng tiến trình. Tôi đã phải sử dụng cờ im lặng (-s) để bảo nó không xuất bất kỳ thông tin nào và viết mã của riêng tôi để xử lý nếu không tải được tệp.


1
Đối với các chương trình không có chế độ im lặng, bạn có thể chuyển hướng đầu ra của chúng sang /dev/null. Ví dụ: some-command > /dev/nullĐiều này sẽ chỉ chuyển hướng đầu ra tiêu chuẩn, chứ không phải đầu ra lỗi (thường là những gì bạn muốn, vì bạn muốn được thông báo về các lỗi). Để chuyển hướng đầu ra lỗi quá, sử dụng some-command &> /dev/null.
Eliah Kagan

Vâng, đó là suy nghĩ đầu tiên của tôi khi viết kịch bản nói trên. Tôi quên tại sao tôi không sử dụng điều đó, có thể là một số hành vi không chuẩn mà phá vỡ giải pháp nói. Tôi biết rằng chế độ tương tác / dài dòng là mặc định trên một số lệnh (Tôi đang xem YOU, scp!), Điều đó có nghĩa là bạn cần phải có đầu ra cho biết để hoạt động trơn tru của các kịch bản shell.
Mange

2

Mặc dù bạn có thể xác định các biến môi trường trong phần trước của mình, nhưng bạn không ở trong tập lệnh shell. Vì vậy, các công trình như sau sẽ không hoạt động:

SOME_DIR=/var/log
MY_LOG_FILE=${SOME_LOG}/some_file.log

BIN_DIR=/usr/local/bin
MY_EXE=${BIN_DIR}/some_executable_file

0 10 * * * ${MY_EXE} some_param >> ${MY_LOG_FILE}

Điều này là do các biến không được diễn giải trong phần trước: tất cả các giá trị được thực hiện một cách đơn giản. Và điều này cũng tương tự nếu bạn bỏ qua dấu ngoặc. Vì vậy, các lệnh của bạn sẽ không chạy và các tệp nhật ký của bạn sẽ không được viết ...

Thay vào đó, bạn phải xác định tất cả các biến môi trường của mình:

SOME_DIR=/var/log
MY_LOG_FILE=/var/log/some_file.log

BIN_DIR=/usr/local/bin
MY_EXE=/usr/local/bin/some_executable_file

0 10 * * * ${MY_EXE} some_param >> ${MY_LOG_FILE}

2

Khi một tác vụ được chạy trong cron, stdin bị đóng. Các chương trình hoạt động khác nhau dựa trên việc stdin có sẵn hay không sẽ hoạt động khác nhau giữa phiên shell và trong cron.

Một ví dụ là chương trình goaccessphân tích tệp nhật ký máy chủ web. Điều này KHÔNG hoạt động trong cron:

goaccess -a -f /var/log/nginx/access.log > output.html

goaccesshiển thị trang trợ giúp thay vì tạo báo cáo. Trong vỏ này có thể được sao chép với

goaccess -a -f /var/log/nginx/access.log > output.html < /dev/null

Cách khắc phục goaccesslà làm cho nó đọc nhật ký từ stdin thay vì đọc từ tệp, vì vậy giải pháp là thay đổi mục crontab thành

cat /var/log/nginx/access.log | goaccess -a > output.html

2

Trong trường hợp của tôi, cron và crontab có chủ sở hữu khác nhau.

KHÔNG làm việc tôi đã có điều này:

User@Uva ~ $ ps -ef | grep cron | grep -v grep
User    2940    7284 pty1     19:58:41 /usr/bin/crontab
SYSTEM   11292     636 ?        22:14:15 /usr/sbin/cro 

Về cơ bản tôi đã phải chạy cron-config và trả lời chính xác các câu hỏi. Có một điểm mà tôi được yêu cầu nhập mật khẩu người dùng Win7 cho tài khoản 'Người dùng' của mình. Từ khi đọc tôi đã làm, có vẻ như đây là một vấn đề bảo mật tiềm ẩn nhưng tôi là quản trị viên duy nhất trên một mạng gia đình duy nhất nên tôi quyết định rằng nó ổn.

Đây là chuỗi lệnh khiến tôi đi:

User@Uva ~ $ cron-config
The cron daemon can run as a service or as a job. The latter is not recommended.
Cron is already installed as a service under account LocalSystem.
Do you want to remove or reinstall it? (yes/no) yes
OK. The cron service was removed.

Do you want to install the cron daemon as a service? (yes/no) yes
Enter the value of CYGWIN for the daemon: [ ] ntsec

You must decide under what account the cron daemon will run.
If you are the only user on this machine, the daemon can run as yourself.
   This gives access to all network drives but only allows you as user.
To run multiple users, cron must change user context without knowing
  the passwords. There are three methods to do that, as explained in
  http://cygwin.com/cygwin-ug-net/ntsec.html#ntsec-nopasswd1
If all the cron users have executed "passwd -R" (see man passwd),
  which provides access to network drives, or if you are using the
  cyglsa package, then cron should run under the local system account.
Otherwise you need to have or to create a privileged account.
  This script will help you do so.
Do you want the cron daemon to run as yourself? (yes/no) no

Were the passwords of all cron users saved with "passwd -R", or
are you using the cyglsa package ? (yes/no) no

Finding or creating a privileged user.
The following accounts were found: 'cyg_server' .
This script plans to use account cyg_server.
Do you want to use another privileged account name? (yes/no) yes
Enter the other name: User

Reenter: User


Account User already exists. Checking its privileges.
INFO: User is a valid privileged account.
INFO: The cygwin user name for account User is User.

Please enter the password for user 'User':
Reenter:
Running cron_diagnose ...
... no problem found.

Do you want to start the cron daemon as a service now? (yes/no) yes
OK. The cron daemon is now running.

In case of problem, examine the log file for cron,
/var/log/cron.log, and the Windows event log (using /usr/bin/cronevents)
for information about the problem cron is having.

Examine also any cron.log file in the HOME directory
(or the file specified in MAILTO) and cron related files in /tmp.

If you cannot fix the problem, then report it to cygwin@cygwin.com.
Please run the script /usr/bin/cronbug and ATTACH its output
(the file cronbug.txt) to your e-mail.

WARNING: PATH may be set differently under cron than in interactive shells.
         Names such as "find" and "date" may refer to Windows programs.


User@Uva ~ $ ps -ef | grep cron | grep -v grep
    User    2944   11780 ?        03:31:10 /usr/sbin/cron
    User    2940    7284 pty1     19:58:41 /usr/bin/crontab

User@Uva ~ $

1
Mặc dù tài liệu tốt, điều này trông giống như một điểm cụ thể của Cygwin; nó thực sự thuộc về Askubfox?
sxc731

2

Trên các máy chủ RHEL7 của tôi, các công việc cron gốc sẽ chạy, nhưng các công việc của người dùng thì không. Tôi thấy rằng không có thư mục chính, các công việc sẽ không chạy (nhưng bạn sẽ thấy các lỗi tốt trong / var / log / cron). Khi tôi tạo thư mục chính, vấn đề đã được giải quyết.


2

Nếu bạn đã chỉnh sửa tệp crontab của mình bằng trình chỉnh sửa windows (thông qua samba hoặc thứ gì đó) và nó đã thay thế các dòng mới bằng \ n \ r hoặc chỉ \ r, cron sẽ không chạy.

Ngoài ra, nếu bạn đang sử dụng /etc/cron.d/* và một trong những tệp đó có \ r trong đó, cron sẽ di chuyển qua các tệp và dừng khi gặp tệp xấu. Không chắc chắn nếu đó là vấn đề?

Sử dụng:

od -c /etc/cron.d/* | grep \r
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.