Lặp lại một lệnh mỗi x khoảng thời gian trong thiết bị đầu cuối?


142

Làm thế nào tôi có thể lặp lại một lệnh mỗi khoảng thời gian, để nó sẽ cho phép tôi chạy các lệnh để kiểm tra hoặc giám sát các thư mục?

Không cần kịch bản, tôi chỉ cần một lệnh đơn giản để được thực thi trong terminal.

Câu trả lời:


219

Bạn có thể sử dụng watchlệnh, đồng hồ được sử dụng để chạy bất kỳ lệnh được chỉ định trong khoảng thời gian thường xuyên.

Mở Terminal và gõ:

watch -n x <your command>

thay đổi x là thời gian tính bằng giây bạn muốn.

Để được trợ giúp thêm bằng cách sử dụng watchlệnh và các tùy chọn của nó, hãy chạy man watchhoặc truy cập Liên kết này .

Ví dụ: sau đây sẽ liệt kê, cứ sau 60 giây , trên cùng một Terminal, nội dung của thư mục Desktop để bạn có thể biết nếu có bất kỳ thay đổi nào xảy ra:

watch -n 60 ls -l ~/Desktop

34
+1 nhưng hãy cẩn thận khi sử dụng mở rộng. Ví dụ: thử sự khác biệt giữa watch -n 1 'echo $COLUMNS'watch -n 1 echo $COLUMNSkhi thay đổi kích thước thiết bị đầu cuối của bạn - cái trước được mở rộng mỗi giây, nhưng cái sau chỉ được mở rộng một lần trước khi watch bắt đầu.
l0b0

Nó hoạt động như một say mê ! Ty nux

Vấn đề tôi gặp phải với giải pháp này là bạn không thể chạy đồng hồ như một quá trình và chỉ để nó chạy ở chế độ nền (ví dụ như với & disown)
Cestarian

2
Có cách nào để sử dụng watchvới lệnh loại "history enable" không? Tôi thích sử dụng watch, nhưng đôi khi tôi cũng muốn xem nhật ký của các lần thực hiện trước đó, thay vì chỉ là lần cuối cùng. Và vâng, tôi biết tôi có thể sử dụng script ( while true) để thực hiện điều này, nhưng sử dụng watchtiện ích thì sạch sẽ hơn rất nhiều!
rinogo

điều này làm việc cho các lệnh đơn giản hơn nhưng với các lệnh pipelined, chuỗi này không hoạt động với tôi .. sau đây là lệnh tôi đã thử => cat api.log | grep 'gọi' | wc -l
Sudip Bhandari

90

Bạn cũng có thể sử dụng lệnh này trong terminal, ngoài câu trả lời của nux:

while true; do <your_command>; sleep <interval_in_seconds>; done

Thí dụ

while true; do ls; sleep 2; done

Lệnh này sẽ in đầu ra trong lskhoảng thời gian 2 giây.

Sử dụng Ctrl+ Cđể dừng quá trình.

Có một vài nhược điểm của watch

  • Nó không thể sử dụng bất kỳ lệnh bí danh.
  • Nếu đầu ra của bất kỳ lệnh nào khá dài, cuộn không hoạt động đúng.
  • Có một số rắc rối để đặt khoảng thời gian tối đa vượt quá giá trị nhất định.
  • watchsẽ diễn giải các chuỗi màu ANSI thông qua các ký tự thoát bằng cách sử dụng -choặc --colortùy chọn. Ví dụ đầu ra của pygmentizesẽ hoạt động nhưng nó sẽ thất bại cho ls --color=auto.

Trong các trường hợp trên, điều này có thể xuất hiện như là một lựa chọn tốt hơn.


watchtồn tại vì điều đó, điều này hơi vô dụng tôi sẽ nói
Bruno Pereira

14
Tôi không khẳng định câu trả lời này là được sử dụng ở nơi đầu tiên. watchlà tốt trong hầu hết các trường hợp. Đó là lý do tại sao tôi đã đề cập "ngoài câu trả lời của nux" lúc đầu. Nhưng có một vài vấn đề với watchví dụ Một người không thể sử dụng bất kỳ lệnh bí danh nào vớiwatch . Lấy ví dụ lllà bí danh ls -laFnhưng không thể được sử dụng với watch. Ngoài ra trong trường hợp nếu đầu ra của bất kỳ lệnh nào khá dài, bạn sẽ gặp rắc rối trong việc cuộn bằng cách sử dụng watch. Trong vài trường hợp đặc biệt, câu trả lời này có thể xuất hiện một lựa chọn tốt hơn.
souravc

@souravc Phiên bản của tôi watchít nhất cho phép -choặc --colortùy chọn cho đầu ra được tô màu.
Lily Chung

8
while sleep xtốt hơn - dễ giết hơn.
d33tah

3
Đây là một thay thế tốt đẹp và, không giống như watch, nó giữ lịch sử lệnh.
adelriosantiago

34

Chỉ muốn đưa ra câu trả lời của souravcnux :

  1. Mặc dù watchsẽ hoạt động hoàn hảo trên Ubuntu, nhưng bạn có thể muốn tránh điều đó nếu bạn muốn "Unix-fu" của mình thuần túy - ví dụ như trên FreeBSD, xem là một lệnh để "rình mò trên một dòng tty" khác.
  2. while true; do command; sleep SECONDS; donecũng có một caveat - lệnh của bạn có thể là khó khăn hơn để giết sử dụng CTR + C . Bạn có thể muốn thích while sleep SECONDS; do command; done- nó không chỉ ngắn hơn mà còn dễ ngắt hơn. Thông báo trước là nó sẽ ngủ trước, sau đó chạy lệnh của bạn, vì vậy bạn sẽ cần đợi một chút SECONDStrước khi lệnh xuất hiện đầu tiên xảy ra.

2
Hy vọng rằng nó có thể được chấp nhận như một câu trả lời thay vì nhận xét - Tôi muốn đưa ra một giải pháp khác ở đây và nhận xét sẽ thực sự khiến tôi ít chú ý hơn.
d33tah

Tại sao chính xác vấn đề nơi bạn đặt sleeptrong whilevòng lặp? Tôi không thể tìm thấy bất kỳ sự khác biệt nào, Ctrl + C đã phá vỡ vòng lặp ngay lập tức bất kể điều gì.
tráng miệng

@dPlay: phụ thuộc vào những gì bạn đang cố gắng thoát ra khỏi tôi đoán. Thông thường, ctrl + c sẽ chỉ giết bạn commandsleepvà chỉ phá vỡ nếu bạn giết true.
d33tah

11

Âm thanh như nhiệm vụ lý tưởng cho crondaemon cho phép chạy các lệnh định kỳ. Chạy crontab -elệnh để bắt đầu chỉnh sửa cấu hình cron người dùng của bạn. Định dạng của nó được ghi lại trong crontab (5) . Về cơ bản, bạn có năm trường liên quan đến không gian, phân tách không gian theo sau là một lệnh:

The time and date fields are:

       field          allowed values
       -----          --------------
       minute         0-59
       hour           0-23
       day of month   1-31
       month          1-12 (or names, see below)
       day of week    0-7 (0 or 7 is Sunday, or use names)

Ví dụ: nếu bạn muốn chạy tập lệnh Python vào mỗi thứ ba, 11 giờ sáng:

0 11 * * 1 python ~/yourscript.py

Ngoài ra còn có một số tên đặc biệt thay thế thời gian, như @reboot. Rất hữu ích nếu bạn cần tạo một thư mục tạm thời. Từ crontab của tôi (được liệt kê với crontab -l):

# Creates a temporary directory for ~/.distcc at boot
@reboot ln -sfn "$(mktemp -d "/tmp/distcc.XXXXXXXX")" "$HOME/.distcc"

4
Câu hỏi hỏi làm thế nào để chạy một cái gì đó định kỳ trong thiết bị đầu cuối. cronchạy phía sau hậu trường chứ không phải trong nhà ga
phía bắc-bradley

5

Nếu bạn đang theo dõi hệ thống tập tin, thì inotifywaitthật tuyệt vời và chắc chắn sẽ tải ít hơn trên hệ thống của bạn.

Thí dụ :

Trong thiết bị đầu cuối loại 1 lệnh này:

$ inotifywait .

Sau đó, trong thiết bị đầu cuối thứ 2 , bất kỳ lệnh nào ảnh hưởng đến thư mục hiện tại,

$ touch newfile

Sau đó, trong thiết bị đầu cuối ban đầu, inotifywait sẽ thức dậy và báo cáo sự kiện

./ CREATE newfile2

Hoặc trong một vòng lặp

$ while true ; do inotifywait . ; done
Setting up watches.  
Watches established.
./ OPEN newfile2
Setting up watches.  
Watches established.
./ OPEN newfile2
Setting up watches.  
Watches established.
./ DELETE newfile
Setting up watches.  
Watches established.
./ CREATE,ISDIR newdir
Setting up watches.  
Watches established.

người dùng nói với bạn, không có kịch bản và có thể anh ta không muốn theo dõi bất cứ điều gì
nux

3
Tôi đã không bảo anh ấy viết một kịch bản, tôi đề nghị rằng nếu họ đang lặp theo thứ tự để theo dõi sự kiện hệ thống tập tin cụ thể, thì inotifywait là hữu ích và sử dụng ít tài nguyên hơn là lặp lại một lệnh. Tôi thường chạy một số lệnh trên một dòng lệnh, ví dụ grep something InALogFile|lessđó có phải là tập lệnh không?
X Tian

đó là một câu trả lời tốt, cố gắng chỉnh sửa nó để trông đơn giản hơn.
nux

3
Điều gì có thể đơn giản hơn .tôi không thể bỏ lệnh.
X Tian

Cảm ơn @XTian, ​​một mệnh lệnh tuyệt vời. Bây giờ tôi cũng thấy trong trang man mà bạn có thể thêm -mvào để liên tục theo dõi mà không cần vòng lặp.
yoniLavi

4

Bạn có thể tạo repeatlệnh của riêng bạn thực hiện các bước sau; tín dụng ở đây :

Đầu tiên, mở .bash_aliasestệp của bạn :

$ xdg-open ~/.bash-aliases

Thứ hai, dán các dòng này ở dưới cùng của tệp và lưu:

repeat() {
n=$1
shift
while [ $(( n -= 1 )) -ge 0 ]
do
    "$@"
done
}

Thứ ba, đóng và mở lại thiết bị đầu cuối của bạn, hoặc gõ:

$ source ~/.bash_aliases

Et voilà! Bây giờ bạn có thể sử dụng nó như thế này:

$ repeat 5 echo Hello World !!!

hoặc là

$ repeat 5 ./myscript.sh

có một lỗi đánh máy nhỏ trong dòng xdg-open ~ / .bash-aliases. nó phải là: xdg-open ~ / .bash_aliases (tức là: gạch dưới)
ssinfod

4

bạn có thể sử dụng crontab. chạy lệnh crontab -evà mở nó bằng trình soạn thảo văn bản ưa thích của bạn, sau đó thêm dòng này

*/10 * * * *  /path-to-your-command

Điều này sẽ chạy lệnh của bạn cứ sau 10 phút

* */4 * * *  /path-to-your-command

Điều này sẽ chạy lệnh của bạn cứ sau 4 giờ

Một giải pháp khả thi khác

$ ..some command...; for i in $(seq X); do $cmd; sleep Y; done

X số lần lặp lại.

Y thời gian chờ đợi để lặp lại.

Thí dụ :

$ echo; for i in $(seq 5); do $cmd "This is echo number: $i"; sleep 1;done

Tại sao đây là một cải tiến? Bạn chỉ cần thêm một bước bổ sung, không cần thiết, bằng cách lưu lệnh dưới dạng một biến. Điều duy nhất làm điều này là i) làm cho nó dài hơn để gõ ii) buộc bạn chỉ sử dụng các lệnh đơn giản, không có đường ống hoặc chuyển hướng, v.v.
terdon

Xóa biến phụ
Maythux 14/05/2015

3

Một mối quan tâm khác với phương pháp "theo dõi" được đề xuất ở trên là nó chỉ hiển thị kết quả khi quá trình được thực hiện. "ngày; ngủ 58; ngày" sẽ hiển thị 2 ngày chỉ sau 59 giây ... Nếu bạn bắt đầu một cái gì đó chạy trong 4 phút, nó sẽ hiển thị chậm nhiều trang nội dung, bạn sẽ không thực sự nhìn thấy nó.

Mặt khác, mối quan tâm với phương pháp "trong khi" là nó không xem xét thời hạn nhiệm vụ.

while true; do script_that_take_between_10s_to_50s.sh; sleep 50; done

Với điều này, kịch bản sẽ chạy đôi khi mỗi phút, đôi khi có thể mất 1m40. Vì vậy, ngay cả khi một cron sẽ có thể chạy nó mỗi phút, ở đây, nó sẽ không.

Vì vậy, để xem đầu ra trên vỏ như được tạo và chờ thời gian yêu cầu chính xác, bạn cần xem xét thời gian trước và sau và lặp lại với thời gian.

Cái gì đó như:

while ( true ); do
  echo Date starting `date`
  before=`date +%s`
  sleep `echo $(( ( RANDOM % 30 )  + 1 ))`
  echo Before waiting `date`
  after=`date +%s`
  DELAY=`echo "60-($after-$before)" | bc`
  sleep $DELAY
  echo Done waiting `date`
done

Điều này sẽ xuất ra điều này:

Như bạn có thể thấy, lệnh chạy mỗi phút:

Date starting Mon Dec 14 15:49:34 EST 2015
Before waiting Mon Dec 14 15:49:52 EST 2015
Done waiting Mon Dec 14 15:50:34 EST 2015

Date starting Mon Dec 14 15:50:34 EST 2015
Before waiting Mon Dec 14 15:50:39 EST 2015
Done waiting Mon Dec 14 15:51:34 EST 2015

Vì vậy, chỉ cần thay thế lệnh "ngủ echo $(( ( RANDOM % 30 ) + 1 ))" bằng những gì bạn muốn và nó sẽ được chạy, trên thiết bị đầu cuối / shell, chính xác mỗi phút. Nếu bạn muốn một lịch trình khác, chỉ cần thay đổi "60" giây với những gì bạn cần.

Phiên bản ngắn hơn không có dòng gỡ lỗi:

while ( true ); do
  before=`date +%s`
  sleep `echo $(( ( RANDOM % 30 )  + 1 ))` # Place you command here
  after=`date +%s`
  DELAY=`echo "60-($after-$before)" | bc`
  sleep $DELAY
done

Trả lời chính tôi ... Nếu lệnh của bạn mất nhiều hơn độ trễ mà bạn định cấu hình, $ DELAY sẽ nhận được giá trị âm và lệnh ngủ sẽ không thành công nên tập lệnh sẽ khởi động lại ngay lập tức. Cần phải nhận thức được điều đó.
jmspaggi
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.