ดำเนินการทุบตีสคริปต์อย่างแท้จริงทุก ๆ 3 วัน


8

ฉันต้องการรันเชลล์สคริปต์อย่างแท้จริงทุกๆ 3 วัน การใช้ crontab กับ01 00 */3 * *จะไม่ปฏิบัติตามเงื่อนไขจริงเพราะจะทำงานในวันที่ 31 และจากนั้นอีกครั้งในวันที่ 1 ของเดือน */3ไวยากรณ์เป็นเช่นเดียวกับการพูดว่า 1,4,7 ... 25,28,31

ควรมีวิธีในการทำให้สคริปต์ตรวจสอบเงื่อนไขและออกจากโปรแกรมหาก 3 วันยังไม่ผ่าน ดังนั้น crontab จะเรียกใช้สคริปต์ทุกวัน แต่สคริปต์จะตรวจสอบว่าผ่านไป 3 วันหรือไม่

ฉันยังพบรหัสบางส่วน แต่มันทำให้ฉันมีข้อผิดพลาดทางไวยากรณ์ความช่วยเหลือใด ๆ ที่จะได้รับการชื่นชม

if (! (date("z") % 3)) {
     exit;
}

main.sh: line 1: syntax error near unexpected token `"z"'
main.sh: line 1: `if (! (date("z") % 3)) {'

4
คุณหมายถึงอะไรกันแน่ มัน*/3ไม่ทำงานอย่างไร "ถ้า 3 วันยังไม่ผ่าน": สามวันนับจากนี้? กรุณาแก้ไขคำถามของคุณและชี้แจง
terdon

4
แท้จริงอักษร? ดูเหมือนว่าคำถาม x / y และคุณอาจต้องการพูดคุยเกี่ยวกับสิ่งที่คุณพยายามทำ คุณพยายามหยุด crontab ไม่ให้เรียกใช้สคริปต์หรือไม่
Journeyman Geek

1
แก้ไขคำถามเพื่ออธิบายว่าทำไมโซลูชัน crontab จึงไม่ทำงาน
Taavi

บางสิ่งที่เหมือนdate("z") % 3 == 0จะประสบปัญหาที่คล้ายกัน: เงื่อนไขจะเป็นเท็จสำหรับสี่วันระหว่าง 29 ธันวาคมและ 3 มกราคมเว้นแต่ว่าธันวาคมเป็นส่วนหนึ่งของปีอธิกสุรทิน
Rhymoid

คำตอบ:


12

หากต้องการยกเลิกและออกจากสคริปต์ทันทีหากการดำเนินการครั้งล่าสุดยังไม่ได้ระบุไว้อย่างน้อยในเวลาที่ผ่านมาคุณสามารถใช้วิธีนี้ซึ่งต้องใช้ไฟล์ภายนอกที่เก็บวันที่และเวลาดำเนินการล่าสุด

เพิ่มบรรทัดเหล่านี้ไปที่ด้านบนของ Bash script ของคุณ:

#!/bin/bash

# File that stores the last execution date in plain text:
datefile=/path/to/your/datefile

# Minimum delay between two script executions, in seconds. 
seconds=$((60*60*24*3))

# Test if datefile exists and compare the difference between the stored date 
# and now with the given minimum delay in seconds. 
# Exit with error code 1 if the minimum delay is not exceeded yet.
if test -f "$datefile" ; then
    if test "$(($(date "+%s")-$(date -f "$datefile" "+%s")))" -lt "$seconds" ; then
        echo "This script may not yet be started again."
        exit 1
    fi
fi

# Store the current date and time in datefile
date -R > "$datefile"

# Insert your normal script here:

อย่าลืมตั้งค่าที่มีความหมายdatefile=และปรับค่าตามseconds=ความต้องการของคุณ ( $((60*60*24*3))ประเมินเป็น 3 วัน)


หากคุณไม่ต้องการไฟล์แยกคุณสามารถเก็บเวลาดำเนินการล่าสุดในการประทับเวลาการแก้ไขของสคริปต์ของคุณ อย่างไรก็ตามนั่นหมายความว่าการเปลี่ยนแปลงใด ๆ กับไฟล์สคริปต์ของคุณจะรีเซ็ตตัวนับ 3 และถือว่าเหมือนว่าสคริปต์นั้นทำงานได้สำเร็จ

ในการนำไปใช้นั้นเพิ่มตัวอย่างด้านล่างไปยังด้านบนของไฟล์สคริปต์ของคุณ:

#!/bin/bash

# Minimum delay between two script executions, in seconds. 
seconds=$((60*60*24*3))

# Compare the difference between this script's modification time stamp 
# and the current date with the given minimum delay in seconds. 
# Exit with error code 1 if the minimum delay is not exceeded yet.
if test "$(($(date "+%s")-$(date -r "$0" "+%s")))" -lt "$seconds" ; then
    echo "This script may not yet be started again."
    exit 1
fi

# Store the current date as modification time stamp of this script file
touch -m -- "$0"

# Insert your normal script here:

อย่าลืมปรับค่าseconds=ความต้องการของคุณ ( $((60*60*24*3))ประเมินเป็น 3 วัน)


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

ไม่จำเป็นต้องเก็บวันที่ด้วย - เพียงแตะที่ไฟล์ทุกครั้งและตรวจสอบว่ามีการลงเวลาหรือไม่
djsmiley2kStaysInside

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

สิ่งนี้สามารถเล่นกอล์ฟได้เล็กน้อยโดยบันทึกการประทับเวลาปัจจุบันลงในไฟล์ (แทนที่จะเป็นวันที่มนุษย์สามารถอ่านได้) ดังนั้นคุณจึงสามารถใช้เวลาที่ผ่านไป$[ $(date +%s) - $(< lastrun) ]ได้ หากสคริปต์ถูกเรียกใช้จาก cron วันละครั้งฉันอาจเพิ่มความหย่อนลงในช่วงเวลาที่กำหนดเพื่อว่าหากการดำเนินการของสคริปต์ล่าช้าประมาณสองวินาทีในครั้งถัดไปจะไม่ข้ามทั้งวัน นั่นคือการตรวจสอบทุกวันหาก 71 ชั่วโมงผ่าน oslt
ilkkachu

พ่อมดกับ datefile ใช้งานได้จริงขอบคุณมาก!
Taavi

12

Cron เป็นเครื่องมือที่ผิดสำหรับเรื่องนี้จริงๆ มีจริงเป็นเครื่องมือที่ใช้กันทั่วไปและ underloved เรียกว่าที่ซึ่งอาจจะทำงาน ที่ของส่วนใหญ่ที่ออกแบบมาสำหรับการใช้งานแบบโต้ตอบและฉันแน่ใจว่าคนที่จะหาวิธีที่ดีกว่าที่จะทำเช่นนี้

ในกรณีของฉันฉันมีสคริปต์ฉันกำลังทำงานอยู่ในรายการใน testjobs.txt และรวมถึงบรรทัดที่อ่าน

ตัวอย่างเช่นฉันจะได้สิ่งนี้เป็น testjobs.txt

echo "cat" >> foo.txt
date >> foo.txt
at now + 3 days < testjobs.txt

ฉันมีสองคำสั่งบริสุทธิ์ซึ่งอาจเป็น shellscripts ของคุณ ฉันรันเสียงสะท้อนเพื่อให้แน่ใจว่าฉันมีเอาต์พุตที่กำหนดไว้และวันที่เพื่อยืนยันคำสั่งที่รันตามต้องการ เมื่อที่รันคำสั่งนี้คำสั่งจะเสร็จโดยเพิ่มงานใหม่เป็นเวลา 3 วัน (ฉันทดสอบด้วยหนึ่งนาที - ซึ่งใช้งานได้)

ฉันค่อนข้างมั่นใจว่าฉันจะถูกเรียกออกมาในลักษณะที่ฉันถูกทารุณกรรม แต่มันเป็นเครื่องมือที่มีประโยชน์สำหรับการตั้งเวลาคำสั่งให้เรียกใช้ในเวลาหรือ x วันหลังจากคำสั่งก่อนหน้า


3
+1 เช่นเดียวatกับวิธีที่ดีกว่าที่นี่ปัญหาของวิธีนี้คือเมื่อใดก็ตามที่คุณเรียกใช้สคริปต์ด้วยตนเองคุณจะต้องเพิ่มชุดของatภารกิจ3 วันทุกวัน
Dewi Morgan

1
+1 แต่มีปัญหาอื่น (นอกเหนือจากที่ @DewiMorgan ชี้ไป) คือว่าหากสคริปต์หนึ่งล้มเหลวสคริปต์ที่ตามมาทั้งหมดจะไม่ถูกเปิดใช้งาน (หากที่อยู่หลังจากจุดล้มเหลว) จนกว่าจะตระหนักว่าสคริปต์นั้นมี ล้มเหลวและเปิดใหม่อีกครั้ง สิ่งนี้อาจไม่ดีหรือบางครั้งก็ดี (เช่น: ล้มเหลวเนื่องจากไม่มีเงื่อนไขอีกต่อไป: เป็นเรื่องดีที่ไม่ลองใหม่ใน 3 วัน) และมีการลอยเล็กน้อยทุกครั้ง (ไม่กี่มิลลิวินาทีถ้าatอยู่ที่ด้านบนหรืออาจมากขึ้นถ้าatอยู่ใกล้ด้านล่างของสคริปต์การดำเนินการยาว)
Olivier Dulac

ที่สามารถส่งอีเมล .... ซึ่งอาจเป็นทางออกสำหรับความล้มเหลว atq และ atrm จะช่วยให้การคัดงานผิดพลาดอาจจะ? ในทางทฤษฎีคุณสามารถเขียนสคริปต์วันที่ที่เฉพาะเจาะจงสำหรับวันที่ แต่ดูเหมือนว่าไม่เหมาะสมและถือ
Geek

ดังนั้นมี cronjob ที่ตรวจสอบการมีอยู่ของการทำงานต่อไปในที่; หากไม่มีให้เพิ่มหนึ่งวันเป็นเวลา 3 วันแล้วเตือน (หรือเรียกใช้ทันทีและตรวจสอบอีกครั้ง)
djsmiley2kStaysInside

3

ก่อนอื่นส่วนรหัสข้างต้นเป็นไวยากรณ์ Bash ที่ไม่ถูกต้องดูเหมือน Perl ประการที่สองzพารามิเตอร์ที่จะdateทำให้มันออกโซนเวลาที่เป็นตัวเลข +%jคือหมายเลขวัน คุณต้องการ:

if [[ ! $(( $(date +%j) % 3 )) ]] ;then
     exit
fi

แต่คุณจะยังคงเห็นความแปลกประหลาดในปลายปี:

$ for i in 364 365  1 ; do echo "Day $i, $(( $i % 3 ))"; done
Day 364, 1
Day 365, 2
Day 1, 1

คุณอาจโชคดีกว่าด้วยการนับจำนวนในไฟล์และทดสอบ / อัปเดตสิ่งนั้น


1
Perl ไม่มีdate()ฟังก์ชันในตัว แต่ดูเหมือนเป็นวันที่ () ใน PHP (ซึ่งzเป็น "วันแห่งปี (เริ่มจาก 0)")
ilkkachu

2

หากคุณสามารถปล่อยให้สคริปต์ทำงานอยู่ตลอดเวลาคุณสามารถทำได้:

while true; do

[inert code here]

sleep 259200
done

การวนซ้ำนี้เป็นจริงเสมอดังนั้นจึงจะเรียกใช้รหัสจากนั้นรอสามวันก่อนเริ่มการวนซ้ำอีกครั้ง


ทำไมwhile trueล่ะ
Jonathan Leffler

ฮะ! จับดี. ฉันไม่จำเป็นต้องใช้สิ่งนั้นในเวลานานฉันลืมไปแล้วว่ามันมีอยู่จริง lol
mkingsbu

2
ในฐานะที่เป็นatวิธีการแก้ปัญหานี้จะลอยไปตามเวลาดำเนินการของสคริปต์แต่ละครั้งที่เรียกใช้ แน่นอนว่าสามารถหลีกเลี่ยงได้โดยการประหยัดเวลาที่สคริปต์จะเริ่มและหยุดจนกว่าจะถึง 3 วัน
ilkkachu

2

คุณสามารถใช้ anacron แทน cron มันถูกออกแบบมาเพื่อทำสิ่งที่คุณต้องการ จาก manpage:

Anacron สามารถใช้เพื่อรันคำสั่งเป็นระยะโดยมีความถี่ที่ระบุในหน่วยวัน ไม่เหมือน cron (8) มันไม่คิดว่าเครื่องจะทำงานอย่างต่อเนื่อง ดังนั้นจึงสามารถใช้กับเครื่องที่ไม่ได้ทำงาน 24 ชั่วโมงต่อวันเพื่อควบคุมงานรายวันรายสัปดาห์และรายเดือนที่มักถูกควบคุมโดย cron

เมื่อดำเนินการ Anacron จะอ่านรายการงานจากไฟล์กำหนดค่าปกติ / etc / anacrontab (ดูที่ anacrontab (5)) ไฟล์นี้มีรายการงานที่ Anacron ควบคุม แต่ละรายการงานระบุช่วงเวลาเป็นวัน, ความล่าช้าเป็นนาที, ตัวระบุงานที่ไม่ซ้ำกัน, และคำสั่งเชลล์

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

หลังจากที่คำสั่งออกแล้ว Anacron จะบันทึกวันที่ในไฟล์ประทับเวลาพิเศษสำหรับงานนั้นเพื่อให้สามารถทราบได้ว่าเมื่อใดที่จะเรียกใช้งานอีกครั้ง ใช้เฉพาะวันที่สำหรับการคำนวณเวลา ไม่ได้ใช้ชั่วโมง


เยี่ยมมากฉันจะทดสอบ Anacron แน่ สงสัยว่าทำไมมันประเมินต่ำเกินไปหากสามารถทำเวทย์มนตร์ดังกล่าวได้
Taavi

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