ทำซ้ำคำสั่ง Unix ทุก ๆ x ตลอดไป


480

มีในตัวคำสั่ง Unix repeatมีอาร์กิวเมนต์แรกคือจำนวนครั้งที่จะทำซ้ำคำสั่งที่คำสั่ง (มีข้อโต้แย้งใด ๆ ) repeatจะถูกระบุโดยการขัดแย้งที่ยังเหลืออยู่

ตัวอย่างเช่น,

% repeat 100 echo "I will not automate this punishment."

จะสะท้อนสตริงที่กำหนด 100 ครั้งแล้วหยุด

ฉันต้องการคำสั่งที่คล้ายกัน - เรียกมันforeverว่า - มันใช้งานได้เหมือนกันยกเว้นอาร์กิวเมนต์แรกคือจำนวนวินาทีในการหยุดระหว่างการเล่นซ้ำและมันจะซ้ำตลอดไป ตัวอย่างเช่น,

% forever 5 echo "This will get echoed every 5 seconds forever and ever."

ฉันคิดว่าฉันถามว่ามีสิ่งนั้นมีอยู่ก่อนที่ฉันจะเขียนหรือไม่ ฉันรู้ว่ามันเหมือนกับสคริปต์ Perl หรือ Python 2 บรรทัด แต่อาจมีวิธีมาตรฐานมากกว่านี้ ถ้าไม่รู้สึกลังเลที่จะโพสต์วิธีแก้ปัญหาในภาษาสคริปต์ที่คุณชื่นชอบสไตล์Rosetta Stone

PS: บางทีวิธีที่ดีกว่าในการทำเช่นนี้คือการพูดคุยทั่วไปrepeatเพื่อใช้ทั้งจำนวนครั้งในการทำซ้ำ (ด้วย -1 ความหมายอินฟินิตี้) และจำนวนวินาทีในการพักระหว่างการทำซ้ำ ตัวอย่างข้างต้นจะกลายเป็น:

% repeat 100 0 echo "I will not automate this punishment."
% repeat -1 5 echo "This will get echoed every 5 seconds forever."

1
ทำไมไม่: ทำซ้ำคำสั่ง [-t time] [-n number] คำสั่ง [args ... ]?
โจนาธาน Leffler

17
เย็น. แต่น่าเสียดายที่ทั้งบน Ubuntu และ AIX ของฉันซ้ำเป็นคำสั่งที่ไม่พบ คุณสามารถทำtype repeatและแจ้งให้เราทราบว่ามาจากไหน

3
ฉันยังอยู่บน Ubuntu และยังไม่ได้ติดตั้งซ้ำ ข้อมูลใด ๆ เกี่ยวกับวิธีการติดตั้งนี้จะเป็นประโยชน์
Rory

7
repeatเป็นคำสั่ง builtin ใน csh และ tcsh
Keith Thompson

2
@KeithThompson, csh, tcsh และ zsh แม้ว่ามันจะเป็นคำหลักที่มากกว่า builtin
Stéphane Chazelas

คำตอบ:


615

ลองwatchคำสั่ง

Usage: watch [-dhntv] [--differences[=cumulative]] [--help] [--interval=<n>] 
             [--no-title] [--version] <command>`

ดังนั้น:

watch -n1  command

จะเรียกใช้คำสั่งทุกวินาที (ดีในทางเทคนิคทุก ๆ วินาทีบวกเวลาที่ใช้ในcommandการรันเป็นwatch(อย่างน้อยprocpsและbusyboxการใช้งาน) เพียงแค่หลับหนึ่งวินาทีในระหว่างการวิ่งสองครั้งcommand) ตลอดไป

คุณต้องการส่งคำสั่งไปยังexecแทนที่จะsh -cใช้-xตัวเลือก:

watch -n1 -x command

บน macOS คุณสามารถรับได้watchจากMac Ports :

port install watch

หรือคุณสามารถรับได้จากHomebrew :

brew install watch

2
คุณสามารถใช้ MacPorts เพื่อติดตั้ง sudo port install watch

10
นอกจากนี้ยังมีใน homebrew (ชงติดตั้งนาฬิกา)
Lyle

28
+1 สำหรับเครื่องมืออันทรงพลังใหม่ ฉันเคยwhile true; do X; sleep Y; done- นี่เป็นวิธีที่ดีกว่า
Adam Matan

4
ปัญหาเกี่ยวกับเครื่องมือนี้ (บน Ubuntu อย่างน้อย) คือมันบังคับให้เต็มหน้าจอดังนั้นหากฉันทิ้งข้อมูลเป็นระยะฉันจะทำข้อมูลก่อนหน้าหายไป
scorpiodawg

4
มันถูกเรียกว่าcmdwatchบน FreeBSD (จากพอร์ต: sysutils/cmdwatch)
Ouki

243

ทุบตี

while+ sleep:

while true
do 
    echo "Hi"
    sleep 1
done

นี่คือสิ่งเดียวกับชวเลขหนึ่งซับ (จากความคิดเห็นด้านล่าง):

while sleep 1; do echo "Hi"; done

ใช้;เพื่อแยกคำสั่งและใช้sleep 1สำหรับการwhileทดสอบเนื่องจากมันจะคืนค่าจริง คุณสามารถใส่คำสั่งเพิ่มเติมในการวนซ้ำ - แยกคำสั่งเหล่านั้นด้วย;


2
ฉันเชื่อว่ามันใช้งานได้เหมือนที่เขียนไว้ในบอร์นเชลล์ทั่วไปเช่นกัน
dmckee

5
@dreeves โดยใช้ ";" ในฐานะตัวคั่นคำสั่งสามารถ execeted ในบรรทัดเดียว ดูคำตอบของ Toony เป็นตัวอย่าง
bbaja42

56
sleep 1 จะคืนค่าเป็นจริงเสมอดังนั้นคุณสามารถใช้มันเป็นเงื่อนไข while ไม่ใช่สิ่งที่อ่านได้มากที่สุดในโลก แต่เป็นสิ่งที่ถูกต้องอย่างแท้จริง: ขณะนอนหลับ 1; ทำเสียงสะท้อน "สวัสดี"; เสร็จสิ้น
David Costa

3
@ David Costa: คุณทำในจุดที่สมเหตุสมผล แต่sleepไม่ได้กลับมาจริงเสมอไป Ī̲ ใช้ลูปดังกล่าว (แม้ว่าจะมีความล่าช้านานกว่า) นั่นก็เพราะว่ามีวิธีที่จะยุติมันได้อย่างงดงามด้วยการฆ่ากระบวนการนอนหลับ
Incnis Mrsi

2
@IncnisMrsi ฉันไม่ได้คิดถึงมันจริง ๆ แล้วมันกลับเป็นศูนย์เฉพาะเมื่อเวลาผ่านไปและไม่เป็นศูนย์เมื่อมันถูกยกเลิกโดยสัญญาณ ขอบคุณที่ชี้นิ้วออกมา
เดวิดคอสตา

71

นี่เป็นเพียงwhile+sleepคำตอบที่สั้นกว่ารุ่นอื่น ๆหากคุณใช้งานประเภทนี้บ่อยครั้งเป็นกิจวัตรประจำวันของคุณการใช้สิ่งนี้จะช่วยให้คุณประหยัดจากการกดปุ่มที่ไม่จำเป็นและหากบรรทัดคำสั่งของคุณเริ่มเข้าใจได้นานขึ้น แต่อันนี้เริ่มต้นด้วยการนอนหลับก่อน

สิ่งนี้มีประโยชน์โดยทั่วไปหากคุณต้องการทำตามสิ่งที่มีเอาต์พุตหนึ่งบรรทัดเช่นโหลดเครื่อง:

while sleep 1; do uptime; done

ใช่. ควรมีการบันทึกไว้ถัดจาก UUOC
Johan

10
และถ้าคุณต้องการให้มันทำงานเหมือน "เฝ้าดู" คุณสามารถทำได้while clear; do date; command;sleep 5; done
Johan

ว้าวขอบคุณสำหรับการwhile sleepรวมกันบันทึก keystokes!
George Y.

45

ปัญหาหนึ่งที่คำตอบทั้งหมดที่โพสต์มีคือเวลาที่คำสั่งถูกดำเนินการสามารถลอยได้ ตัวอย่างเช่นถ้าคุณทำsleep 10ระหว่างคำสั่งและคำสั่งใช้เวลา 2 วินาทีในการเรียกใช้แล้วมันจะทำงานทุก 12 วินาที หากต้องใช้เวลาในการผันแปรจำนวนมากดังนั้นในระยะยาวจะไม่สามารถคาดการณ์ได้

นี่อาจเป็นสิ่งที่คุณต้องการ ถ้าเป็นเช่นนั้นใช้หนึ่งในวิธีการแก้ปัญหาอื่น ๆ หรือใช้วิธีนี้ แต่ลดความซับซ้อนของการsleepโทร

สำหรับการแก้ปัญหาหนึ่งนาทีงาน cron จะทำงานในเวลาที่กำหนดโดยไม่คำนึงว่าแต่ละคำสั่งใช้เวลานานเท่าใด (อันที่จริงงาน cron ใหม่จะเปิดขึ้นแม้ว่างานก่อนหน้านี้ยังทำงานอยู่)

นี่เป็นสคริปต์ Perl ง่าย ๆ ที่หลับจนกระทั่งถึงช่วงต่อไปดังนั้นตัวอย่างเช่นในช่วงเวลา 10 วินาทีคำสั่งอาจทำงานที่ 12:34:00, 12:34:10, 12:34:20 เป็นต้น คำสั่งตัวเองใช้เวลาหลายวินาที หากคำสั่งรันมากกว่าintervalวินาทีช่วงเวลาถัดไปจะถูกข้าม (ไม่เหมือน cron) ช่วงเวลานั้นถูกคำนวณเทียบกับยุคดังนั้นช่วงเวลา 86400 วินาที (1 วัน) จะทำงานในเวลาเที่ยงคืน UTC

#!/usr/bin/perl

use strict;
use warnings;

if (scalar @ARGV < 2) {
    die "Usage: $0 seconds command [args...]\n";
}

$| = 1;  # Ensure output appears

my($interval, @command) = @ARGV;

# print ">>> interval=$interval command=(@command)\n";

while (1) {
    print "sleep ", $interval - time % $interval, "\n";
    sleep $interval - time % $interval;
    system @command; # TODO: Handle errors (how?)
}


1
ง่ายในการทุบตีเพื่อลดการดริฟท์ (แม้ว่ามันอาจลอยอยู่เหนือหน้าต่างการใช้งานนานมากเนื่องจากคำสั่ง sleep และทุบตีตัวเองสะสมเวลาดำเนินการเล็ก ๆ ของมัน): while :; do sleep 1m & command; wait; done
คณิตศาสตร์

1
@math: ฉลาด มันไม่ทำงานหากคุณมีกระบวนการพื้นหลังอื่น ๆ ที่ทำงานในเชลล์ปัจจุบัน ( waitจะรอกระบวนการทั้งหมด) นั่นคือแน่นอนโดยการเปลี่ยนwaitไปwait $!ซึ่ง$!เป็น PID ของsleepกระบวนการ โพสต์สิ่งนี้เป็นคำตอบและฉันจะโหวตขึ้น แต่มันจะสร้างเอาต์พุตที่ไม่เกี่ยวข้องในเชลล์แบบโต้ตอบ
Keith Thompson

29

ฉันคิดว่าคำตอบทั้งหมดที่นี่จนถึงตอนนี้อาจซับซ้อนเกินไปหรือตอบคำถามอื่นแทน:

  • "วิธีการเรียกใช้โปรแกรมซ้ำ ๆ เพื่อให้มีวินาที X ล่าช้าระหว่างเมื่อโปรแกรมเสร็จสิ้นและเริ่มต้นต่อไป"

คำถามที่แท้จริงคือ:

  • "วิธีเรียกใช้โปรแกรมทุก ๆ X วินาที"

นี่เป็นสองสิ่งที่แตกต่างกันมากเมื่อคำสั่งใช้เวลาในการทำให้เสร็จ

ยกตัวอย่างสคริปต์foo.sh(อ้างว่านี่เป็นโปรแกรมที่ใช้เวลาสองสามวินาทีจึงจะเสร็จสมบูรณ์)

#!/bin/bash
# foo.sh
echo `date +"%H:%M:%S"` >> output.txt;
sleep 2.5;
# ---

คุณต้องการที่จะทำงานนี้ทุกวินาทีและส่วนใหญ่จะแนะนำหรือwatch -n1 ./foo.sh while sleep 1; do ./foo.sh; doneอย่างไรก็ตามสิ่งนี้จะให้ผลลัพธ์:

15:21:20
15:21:23
15:21:27
15:21:30
15:21:34

ซึ่งไม่ได้ถูกเรียกใช้ทุกวินาที แม้จะมีการ-pตั้งค่าสถานะตามที่man watchหน้าแนะนำอาจแก้ไขปัญหานี้ผลลัพธ์ก็เหมือนกัน

วิธีง่ายๆในการทำงานให้สำเร็จตามที่ต้องการซึ่งบางการสัมผัสคือการเรียกใช้คำสั่งในพื้นหลัง ในคำอื่น ๆ :

while sleep 1; do (./foo.sh &) ; done

และนั่นคือทั้งหมดที่มีให้มัน

คุณสามารถเรียกใช้ทุก ๆ 500 มิลลิวินาทีด้วยsleep 0.5หรืออะไรก็ได้


1
ผู้ที่ลงคะแนนในคำตอบที่แตกต่างกันไม่เข้าใจความสง่างามของคำตอบของคุณ ...
Serge Stroobandt

สิ่งนี้ดีถ้าโปรแกรมของคุณมีผลข้างเคียง หากโปรแกรมใช้เวลานานกว่าช่วงเวลาผลข้างเคียงอาจรบกวน (เช่นการเขียนทับไฟล์) หากโปรแกรมรออย่างอื่นและสิ่งอื่นกำลังดำเนินอยู่ตลอดไปแสดงว่าคุณเริ่มงานพื้นหลังมากขึ้นเรื่อย ๆ ใช้ด้วยความระมัดระวัง
John Moeller

4
สามารถสลับลำดับของพื้นหลังเพื่อให้แน่ใจว่ามีการรัน. / foo.sh มากกว่าหนึ่งครั้ง แต่จะไม่เร็วกว่า 1 ต่อวินาที: while :; do sleep 1 & ./foo.sh; wait; done
คณิตศาสตร์

ใช่มันจะลอยสองสามมิลลิวินาทีในแต่ละวง แต่มันจะ ทำdate +"%H:%M:%S.%N"ใน foo.sh เพื่อดูว่าเศษส่วนจะเพิ่มอย่างช้าๆในแต่ละลูป
Isaac

ใช่มันเป็นความจริงว่าคำตอบส่วนใหญ่ไม่ได้ตัวอักษรที่อยู่ในคำถาม แต่มันเป็นเดิมพันที่เกือบจะปลอดภัยที่พวกเขาตอบในสิ่งที่ OP ต้องการ มันจะเป็นการเดิมพันที่ปลอดภัยกว่าถ้า OP ยอมรับคำตอบจริง ๆ ... แต่นี่เป็นสิ่งที่ดีถ้าคุณตระหนักถึงผลข้างเคียงที่อาจเกิดขึ้นและคุณมั่นใจว่าเวลารันโดยเฉลี่ยของคำสั่งจะไม่เกินเวลารอบ
Auspex

17

ในbash:

bash -c 'while [ 0 ]; do echo "I will not automate this punishment in absurdum."; done'

( echoอาจถูกแทนที่ด้วยคำสั่งใด ๆ ...

หรือในperl:

perl -e 'for (;1;) {print "I will not automate this punishment in absurdum.\n"}'

ที่print "I will not automate this punishment in absurdum.\n"สามารถถูกแทนที่ด้วยคำสั่ง "ใด ๆ " ล้อมรอบด้วย backticks (`)

และสำหรับการหยุดชั่วคราวเพิ่มsleepคำสั่งภายในวงสำหรับ:

bash -c 'while [ 0 ]; do echo "I will not automate this punishment in absurdum."; sleep 1; done'

และ

perl -e 'for (;1;) {print "I will not automate this punishment in absurdum.\n"; sleep 1}'

16
while [ 0 ]เป็นวิธีที่ไม่ดีในการเขียน มันหมายความว่า0เป็นสตริงที่มีความยาว> 0 while [ 1 ]หรือwhile [ jeff ]จะทำในสิ่งเดียวกัน while trueดีกว่าที่จะเขียน
มิเคล

5
@Mikel: หรือwhile :
Keith Thompson

10

ทุบตีล่าสุด> = 4.2 ภายใต้เคอร์เนล Linux ล่าสุดคำตอบตาม

เพื่อ จำกัด เวลาดำเนินการไม่มีส้อม ! ใช้ในตัวเท่านั้น

สำหรับเรื่องนี้ผมใช้ฟังก์ชั่นในตัวแทนread sleepUnfortunely นี้จะไม่ทำงานกับNottyประชุม

ฟังก์ชันด่วน" repeat" ตามที่ร้องขอ:

repeat () {
   local repeat_times=$1 repeat_delay=$2 repeat_foo repeat_sleep
   read -t .0001 repeat_foo
   if [ $? = 1 ] ;then
       repeat_sleep() { sleep $1 ;}
   else
       repeat_sleep() { read -t $1 repeat_foo; }
   fi
   shift 2
   while ((repeat_times)); do
        ((repeat_times=repeat_times>0?repeat_times-1:repeat_times))
        "${@}"
        ((repeat_times))&& ((10#${repeat_delay//.})) &&
            repeat_sleep $repeat_delay
   done
}

ทดสอบเล็กน้อยด้วยสตริงที่ยกมา:

repeat 3 0 printf "Now: %(%T)T, Hello %s.\n" -1 Guy
Now: 15:13:43, Hello Guy.
Now: 15:13:43, Hello Guy.
Now: 15:13:43, Hello Guy.

repeat -1 .5 printf "Now: %(%T)T, Hello %s.\n" -1 Guy
Now: 15:14:14, Hello Guy.
Now: 15:14:14, Hello Guy.
Now: 15:14:15, Hello Guy.
Now: 15:14:15, Hello Guy.
Now: 15:14:16, Hello Guy.
Now: 15:14:16, Hello Guy.
Now: 15:14:17, Hello Guy.
Now: 15:14:17, Hello Guy.
Now: 15:14:18, Hello Guy.
Now: 15:14:18, Hello Guy.
^C

ขึ้นอยู่กับความละเอียดและระยะเวลาของคำสั่งที่ส่ง ...

ภายใต้เคอร์เนล Linux ล่าสุดมี procfile /proc/timer_listที่มีข้อมูลเวลาเป็นนาโนวินาที

หากคุณต้องการรันคำสั่งทีละครั้งคำสั่งของคุณจะต้องสิ้นสุดในเวลาไม่ถึงวินาที! และจากที่นั่นคุณจะต้องsleepเท่านั้นส่วนที่เหลือที่สองปัจจุบัน

หากการหน่วงเวลามีความสำคัญมากกว่าและคำสั่งของคุณไม่จำเป็นต้องใช้เวลามากคุณสามารถ:

command=(echo 'Hello world.')
delay=10
while :;do
    printf -v now "%(%s)T" -1
    read -t $(( delay-(now%delay) )) foo
    ${command[@]}
  done.

แต่ถ้าเป้าหมายของคุณคือการได้รายละเอียดปลีกย่อยคุณต้อง:

ใช้ข้อมูลนาโนวินาทีเพื่อรอจนกว่าจะเริ่มวินาที ...

สำหรับสิ่งนี้ฉันได้เขียนฟังก์ชั่นทุบตีเล็ก ๆ น้อย ๆ :

# bash source file for nano wait-until-next-second

mapfile  </proc/timer_list _timer_list
for ((_i=0;_i<${#_timer_list[@]};_i++));do
    ((_c+=${#_timer_list[_i]}))
    [[ ${_timer_list[_i]} =~ ^now ]] && TIMER_LIST_READ=$_c
    [[ ${_timer_list[_i]} =~ offset:.*[1-9] ]] && \
        TIMER_LIST_OFFSET=${_timer_list[_i]//[a-z.: ]} && \
        break
done
unset _i _timer_list _c
readonly TIMER_LIST_OFFSET TIMER_LIST_READ
waitNextSecondHires() {
    local nsnow nsslp
    read -N$TIMER_LIST_READ nsnow </proc/timer_list
    nsnow=${nsnow%% nsecs*}
    nsnow=$((${nsnow##* }+TIMER_LIST_OFFSET))
    nsslp=$((2000000000-10#${nsnow:${#nsnow}-9}))
    read -t .${nsslp:1} foo
}

หลังจากจัดหาพวกเขาคุณสามารถ:

command=(echo 'Hello world.')
while :;do
    waitNextSecondHires
    ${command[@]}
  done.

เรียกใช้${command[@]}โดยตรงบนบรรทัดคำสั่งเปรียบเทียบกับ

command=(eval "echo 'Hello world.';sleep .3")
while :;do
    waitNextSecondHires
    ${command[@]}
  done.

สิ่งนี้จะต้องให้ผลลัพธ์ที่เหมือนกันทุกประการ

ว่าจ้างฟังก์ชัน " repeat" ตามที่ร้องขอ:

คุณสามารถหาแหล่งนี้ได้:

mapfile  </proc/timer_list _timer_list
for ((_i=0;_i<${#_timer_list[@]};_i++));do
    ((_c+=${#_timer_list[_i]}))
    [[ ${_timer_list[_i]} =~ ^now ]] && TIMER_LIST_READ=$_c
    [[ ${_timer_list[_i]} =~ offset:.*[1-9] ]] && \
        TIMER_LIST_OFFSET=${_timer_list[_i]//[a-z.: ]} && \
        break
done
unset _i _timer_list _c
readonly TIMER_LIST_OFFSET TIMER_LIST_READ

repeat_hires () {
    local repeat_times=$1 repeat_delay=$2 repeat_foo repeat_sleep repeat_count
    read -t .0001 repeat_foo
    if [ $? = 1 ] ;then
        repeat_sleep() { sleep $1 ;}
    else
        repeat_sleep() { read -t $1 repeat_foo; }
    fi
    shift 2
    printf -v repeat_delay "%.9f" $repeat_delay
    repeat_delay=${repeat_delay//.}
    read -N$TIMER_LIST_READ nsnow </proc/timer_list
    nsnow=${nsnow%% nsec*}
    started=${nsnow##* }
    while ((repeat_times)); do
        ((repeat_times=repeat_times>0?repeat_times-1:repeat_times))
        "${@}"
        ((repeat_times)) && ((10#$repeat_delay)) && {
            read -N$TIMER_LIST_READ nsnow </proc/timer_list
            nsnow=${nsnow%% nsec*}
            nsnow=${nsnow##* }
            (( (nsnow - started) / 10#$repeat_delay - repeat_count++ )) &&
                printf >&2 "WARNING: Command '%s' too long for %f delay.\n" \
                           "${*}" ${repeat_delay:0:${#repeat_delay}-9
                           }.${repeat_delay:${#repeat_delay}-9}
            printf -v sleep "%010d" $((
                10#$repeat_delay - ( ( nsnow - started ) % 10#$repeat_delay ) ))
            repeat_sleep ${sleep:0:${#sleep}-9}.${sleep:${#sleep}-9}
        }
    done
}

จากนั้นลอง:

time repeat_hires 21 .05 sh -c 'date +%s.%N;sleep .01'
1480867565.152022457
1480867565.201249108
1480867565.251333284
1480867565.301224905
1480867565.351236725
1480867565.400930482
1480867565.451207075
1480867565.501212329
1480867565.550927738
1480867565.601199721
1480867565.651500618
1480867565.700889792
1480867565.750963074
1480867565.800987954
1480867565.853671458
1480867565.901232296
1480867565.951171898
1480867566.000917199
1480867566.050942638
1480867566.101171249
1480867566.150913407

real    0m1.013s
user    0m0.000s
sys     0m0.016s

time repeat_hires 3 .05 sh -c 'date +%s.%N;sleep .05'
1480867635.380561067
WARNING: Command 'sh -c date +%s.%N;sleep .05' too long for 0.050000 delay.
1480867635.486503367
WARNING: Command 'sh -c date +%s.%N;sleep .05' too long for 0.050000 delay.
1480867635.582332617

real    0m0.257s
user    0m0.000s
sys     0m0.004s

read -tเป็นตัวในขณะที่sleepไม่ นี้อาจมีผลกระทบชายแดน (เช่นกดปุ่ม [คีย์: กลับ] ขัดจังหวะการนอนหลับอย่างเงียบ ๆ) แต่สิ่งนี้สามารถได้รับการปฏิบัติโดยการทดสอบ$foo
F. Hauri

คำตอบที่น่าประทับใจมาก
gena2x

4

สนใจที่จะลองสิ่งนี้ (Bash) หรือไม่

forever ()   {
    TIMES=shift;
    SLEEP=shift;
    if [ "$TIMES" = "-1" ]; then  
        while true;
        do 
            $@
            sleep $SLEEP
        done
    else
        repeat "$TIMES" $@ 
    fi; }

ฉันไม่ร้อนที่เปลือกดังนั้นการปรับปรุงยินดีต้อนรับ และฉันดูเหมือนจะไม่มีคำสั่ง "ซ้ำ" ใน distro ของฉัน

2
repeatเฉพาะกับ csh และ tcsh
Keith Thompson

2
@ KeithThompson: และ zsh
Thor

4

Perl

#!/usr/bin/env perl
# First argument is number of seconds to sleep between repeats, remaining
# arguments give the command to repeat forever.

$sleep = shift;
$cmd = join(' ', @ARGV);

while(1) {
  system($cmd);
  sleep($sleep); 
}

4

Bash และเชลล์ที่เป็นญาติของมันบางตัวมี(( ... ))สัญกรณ์ที่สะดวกในการประเมินนิพจน์ทางคณิตศาสตร์

เพื่อเป็นคำตอบสำหรับความท้าทายครั้งที่สามของคุณที่ควรกำหนดค่าการนับซ้ำและการหน่วงเวลาระหว่างการทำซ้ำแต่ละครั้งนี่เป็นวิธีหนึ่งที่ทำได้

repeat=10
delay=1

i=0
while (( i++ < repeat )); do
  echo Repetition $i
  sleep $delay
done

คำตอบนี้ยังทนทุกข์ทรมานจากดริฟท์ระยะเวลาที่ครอบคลุมในคี ธคำตอบ


นี่คือสิ่งที่ดีที่สุด
Ahmad Awais

3

ตามที่กล่าวไว้โดย gbrandt หากwatchคำสั่งพร้อมใช้งานให้ใช้จริง อย่างไรก็ตามระบบ Unix บางระบบไม่ได้ติดตั้งไว้เป็นค่าเริ่มต้น

นี่เป็นอีกวิธีการหนึ่งที่มีไวยากรณ์และเอาต์พุตแตกต่างกันเล็กน้อย (ทำงานใน BASH และ SH):

while [ 1 ] ; do
    <cmd>
    sleep <x>
    echo ">>>>>>>>>>>>>" `date` ">>>>>>>>>>>>>>"
done

แก้ไข: ฉันได้ลบ "." บางส่วน ในคำสั่ง echo ล่าสุด ... โฮลด์จาก Perl วันของฉัน;)


3
while [ 1 ]ทำงานเพียงเพราะ 1 while [ -n 1 ]จะถือว่าเป็นสตริงเช่นเดียวกับ while [ 0 ]หรือwhile [ jeff ]จะทำในสิ่งเดียวกัน while trueทำให้รู้สึกมากขึ้น
Mikel

3

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

* * * * * my_precious_command

โปรดดูตัวอย่างบทช่วยสอนเพิ่มเติม นอกจากนี้คุณยังสามารถตั้งค่าการกำหนดเวลาอย่างง่ายดายโดยใช้เครื่องกำเนิดไฟฟ้ารหัส Crontab


3

ถ้าเรามีทั้งคู่ล่ะ

นี่คือความคิด: ด้วย "ช่วงเวลา" เท่านั้นมันจะทำซ้ำอย่างถาวร ด้วย "interval" และ "times" มันจะทำซ้ำจำนวนครั้งนี้โดยคั่นด้วย "interval"

การใช้งาน:

$ loop [interval [times]] command

ดังนั้นอัลกอริทึมจะเป็น:

  • รายการสินค้า
  • ถ้า $ 1 มีตัวเลขเท่านั้นมันเป็นช่วงเวลา (ค่าเริ่มต้น 2)
  • ถ้า $ 2 มีตัวเลขเท่านั้นมันคือจำนวนครั้ง (ไม่มีที่สิ้นสุดเริ่มต้น)
  • ในขณะที่วนรอบด้วยพารามิเตอร์เหล่านี้
    • หลับ "ช่วงเวลา"
    • หากได้รับจำนวนครั้งที่ลดลง var จนกว่าจะถึง

ดังนั้น:

loop() {
    local i=2 t=1 cond

    [ -z ${1//[0-9]/} ] && i=$1 && shift
    [ -z ${1//[0-9]/} ] && t=$1 && shift && cond=1
    while [ $t -gt 0 ]; do 
        sleep $i
        [ $cond ] && : $[--t]
        $@
    done
}

หมายเหตุ: มันใช้งานไม่ได้กับโฟลทแม้sleepจะยอมรับมัน
บารอน

2

ฉันสร้างการเปลี่ยนแปลงในคำตอบของ swalog กับเขาคุณต้องรอ X วินาทีสำหรับการทำซ้ำครั้งแรกฉันยังทำงานของฉันในเบื้องหน้าดังนั้น ..

./foo.sh;while sleep 1; do (./foo.sh) ; done

1

ด่วนสกปรกและอาจเป็นอันตรายต่อบูต แต่ถ้าคุณรักการผจญภัยและรู้ว่าสิ่งที่คุณทำวางนี้ในrepeat.shและchmod 755มัน

while true
do 
    eval $1 
    sleep $2 
done

เรียกใช้ด้วย ./repeat.sh <command> <interval>

ประสาทสัมผัสของฉันบอกว่านี่อาจเป็นวิธีที่ชั่วร้ายในการทำสิ่งนี้


8
Eval !? เพื่ออะไร? sleep $1; shift; "$@"หรือคล้ายกันจะดีกว่ามาก
มิเคล

Dunno ทำไมนี่ถึง -2 eval อาจ overkill ... ยกเว้นเมื่อคุณต้องการ Eval ให้คุณได้สิ่งต่าง ๆ เช่นการเปลี่ยนเส้นทางไปยังบรรทัดคำสั่ง
Johan

1

คุณสามารถเรียกใช้สคริปต์จาก init (เพิ่มบรรทัดใน / etc / inittab) สคริปต์นี้จะต้องเรียกใช้คำสั่งของคุณหลับในเวลาที่คุณต้องการรอจนกว่าจะเรียกใช้สคริปต์อีกครั้งและออกจากมัน เริ่มต้นจะเริ่มสคริปต์ของคุณอีกครั้งหลังจากออก


1

วิธีง่ายๆในการทำซ้ำงานจาก crontab ด้วยช่วงเวลาน้อยกว่าหนึ่งนาที (ตัวอย่าง 20 วินาที):

crontab: * * * * * script.sh

script.sh:

#!/bin/bash
>>type your commands here.

sleep 20
>>retype your commands here.

sleep 20
>>retype your commands here.

1

คุณสามารถรับพลังงานจากหลามล่ามจากเปลือก

python3 -c "import time, os
while True:
    os.system('your command')
    time.sleep(5)

แทนที่ห้าในเวลาใด ๆ (วินาที) ที่คุณต้องการ

ข้อควรระวัง: การส่งคืนใช้ SHIFT + ENTER เพื่อส่งคืนอินพุตในเชลล์ และอย่าลืมที่จะพิมพ์ 4 เว้นวรรคเยื้องในแต่ละบรรทัดในขณะที่วง


โปรดทราบว่าpython's os.system()รันเปลือกจะตีความบรรทัดคำสั่งดังนั้นการกล่าวอ้างpythonเพื่อเรียกใช้เปลือกหอยในวงที่จะเรียกใช้คำสั่งเป็นระยะเป็น overkill บิต คุณอาจทำทุกอย่างในเปลือกได้เช่นกัน
Stéphane Chazelas

ฉันเห็นด้วยกับคุณ. อย่างไรก็ตามมีการนอนหลับ 5 วินาทีตามที่คุณอธิบายไว้ในแต่ละวง ดังนั้นค่าใช้จ่ายเพิ่มเติมจากการเริ่มเปลือกใหม่สามารถถูกละเว้น หากค่าใช้จ่ายนี้ทำให้ระยะเวลานานกว่าที่คาดหมายคุณสามารถลดเวลานอนหลับได้ตามความต้องการ
pah8J

0

วิธีนี้ใช้งานได้ใน MacOSX 10.7 มันใช้งานได้อย่างยอดเยี่ยม

bash -c 'while [ 0 ]; do \
      echo "I will not automate this punishment in absurdum."; done'

ในกรณีของฉัน

bash -c 'while [ 0 ]; do ls; done'

หรือ

bash -c 'while [ 0 ]; do mv "Desktop/* Documents/Cleanup"; done'

ทำความสะอาดเดสก์ทอปของฉันอย่างต่อเนื่อง


1
คุณหมายถึงมีsleepคำสั่งที่นั่นหรือไม่?
Keith Thompson

4
while [ 0 ]เป็นวิธีที่แปลกในการเขียนลูปไม่สิ้นสุด มันใช้งานได้เพราะtestคำสั่ง (หรือเรียกอีกอย่างว่า[) ถือว่าสตริงที่ไม่ว่างเปล่าเป็นจริง เป็นสำนวนเพิ่มเติมหรือถ้าคุณต้องการคุณสามารถใช้while : ; do ... ; done while true ; do ... ; done
Keith Thompson


0

หากต้องการเรียกใช้คำสั่งซ้ำ ๆ ในหน้าต่างคอนโซลฉันมักจะเรียกใช้สิ่งนี้:

while true; do (run command here); done

สิ่งนี้ใช้ได้กับหลายคำสั่งเช่นกันเพื่อแสดงนาฬิกาที่อัพเดตอย่างต่อเนื่องในหน้าต่างคอนโซล:

while true; do clear; date; sleep 1; done


ทำไมต้องลงคะแนน คุณสามารถดูว่านี่เป็นวิธีการทำงานโดยการคัดลอกและวางตัวอย่างลงในหน้าต่างเทอร์มินัล
Thomas Bratt

ฉันคิดว่าคุณโดนโหวตเพราะมันอันตรายนิดหน่อยและกินซีพียู
ojblass

0
#! /bin/sh

# Run all programs in a directory in parallel
# Usage: run-parallel directory delay
# Copyright 2013 by Marc Perkel
# docs at http://wiki.junkemailfilter.com/index.php/How_to_run_a_Linux_script_every_few_seconds_under_cron"
# Free to use with attribution

if [ $# -eq 0 ]
then
   echo
   echo "run-parallel by Marc Perkel"
   echo
   echo "This program is used to run all programs in a directory in parallel" 
   echo "or to rerun them every X seconds for one minute."
   echo "Think of this program as cron with seconds resolution."
   echo
   echo "Usage: run-parallel [directory] [delay]"
   echo
   echo "Examples:"
   echo "   run-parallel /etc/cron.20sec 20"
   echo "   run-parallel 20"
   echo "   # Runs all executable files in /etc/cron.20sec every 20 seconds or 3 times a minute."
   echo 
   echo "If delay parameter is missing it runs everything once and exits."
   echo "If only delay is passed then the directory /etc/cron.[delay]sec is assumed."
   echo
   echo 'if "cronsec" is passed then it runs all of these delays 2 3 4 5 6 10 12 15 20 30'
   echo "resulting in 30 20 15 12 10 6 5 4 3 2 executions per minute." 
   echo
   exit
fi

# If "cronsec" is passed as a parameter then run all the delays in parallel

if [ $1 = cronsec ]
then
   $0 2 &
   $0 3 &
   $0 4 &
   $0 5 &
   $0 6 &
   $0 10 &
   $0 12 &
   $0 15 &
   $0 20 &
   $0 30 &
   exit
fi

# Set the directory to first prameter and delay to second parameter

dir=$1
delay=$2

# If only parameter is 2,3,4,5,6,10,12,15,20,30 then automatically calculate 
# the standard directory name /etc/cron.[delay]sec

if [[ "$1" =~ ^(2|3|4|5|6|10|12|15|20|30)$ ]]
then
   dir="/etc/cron.$1sec"
   delay=$1
fi

# Exit if directory doesn't exist or has no files

if [ ! "$(ls -A $dir/)" ]
then
   exit
fi

# Sleep if both $delay and $counter are set

if [ ! -z $delay ] && [ ! -z $counter ]
then
   sleep $delay
fi

# Set counter to 0 if not set

if [ -z $counter ]
then
   counter=0
fi

# Run all the programs in the directory in parallel
# Use of timeout ensures that the processes are killed if they run too long

for program in $dir/* ; do
   if [ -x $program ] 
   then
      if [ "0$delay" -gt 1 ] 
      then
         timeout $delay $program &> /dev/null &
      else
         $program &> /dev/null &
      fi
   fi
done

# If delay not set then we're done

if [ -z $delay ]
then
   exit
fi

# Add delay to counter

counter=$(( $counter + $delay ))

# If minute is not up - call self recursively

if [ $counter -lt 60 ]
then
   . $0 $dir $delay &
fi

# Otherwise we're done

0

ด้วยzshและการsleepใช้งานที่ยอมรับอาร์กิวเมนต์จุดลอย:

typeset -F SECONDS=0 n=0
repeat 100 {cmd; sleep $(((n+=3) - SECONDS))}

หรือสำหรับforever:

for ((;;)) {cmd; sleep $(((n+=3) - SECONDS))}

ถ้าคุณsleepไม่สนับสนุนลอยคุณสามารถ redefine เป็นห่อหุ้มรอบzsh's zselectbuiltin:

zmodload zsh/zselect
sleep() zselect -t $((($1 * 100) | 0))

-1

... ฉันสงสัยว่าจะสามารถสร้างวิธีแก้ปัญหาที่ซับซ้อนได้มากเพียงใดเมื่อแก้ไขปัญหานี้

มันง่ายมาก ...

open /etc/crontab 

ใส่ 1 บรรทัดถัดไปที่ท้ายไฟล์เช่น:

*/NumberOfSeconds * * * * user /path/to/file.sh

หากคุณต้องการเรียกใช้บางสิ่งบางอย่างทุก 1 วินาทีเพียงแค่ใส่:

*/60 * * * * root /path/to/file.sh 

where that file.sh could be chmod 750 /path/to/file.sh

และด้านในของ file.sh นั้นควรเป็น:

#!/bin/bash 
#What does it do
#What is it runned by

your code or commands

และนั่นคือทั้งหมด!

สนุก!


6
สิ่งนี้ไม่ถูกต้อง * / 60 จะทำงานทุก ๆ 60 นาทีและ * / 5 เช่นทุกๆ 5 นาที
mika

1
ไม่อนุญาตวินาทีใน crontab
GAD3R

ทดสอบสิ่งของของคุณก่อนตอบด้วยอึผิด
sjas

-1
until ! sleep 60; do echo $(date); command; command; command; done

ทำงานได้สำหรับฉัน

  1. ฉันไม่ต้องการมันทุก ๆ 60 วินาที
  2. "เฝ้าดู" ไม่ดูคำสั่งในทุกระบบ
  3. "เฝ้าดู" สามารถใช้คำสั่งเดียวเท่านั้น (หรือไฟล์สคริปต์)
  4. ทำให้การนอนหลับอยู่ในสภาพที่ดีแทนที่จะทำให้ร่างกายวนซ้ำได้ดีขึ้น (ดังนั้นการอ้างสิทธิ์ในการตอบคำถามที่คล้ายกันใน stackoverflow น่าเสียดายที่ฉันสามารถค้นหาได้ในขณะนี้)
  5. ฉันต้องการที่จะรันมันหนึ่งครั้งก่อนที่จะเกิดความล่าช้าดังนั้นฉันจึงใช้จนกระทั่งแทนที่จะเป็นในขณะนั้น

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