Chạy lệnh sau một khoảng thời gian nhất định đã trôi qua?


23

Nếu tôi đang thực hiện một quy trình dài, có cách nào tôi có thể thực hiện một số lệnh dựa trên thời gian không?

Ví dụ: tôi đang chạy một quá trình thực sự dài trong khoảng 10 phút.

Sau 5 phút, tôi muốn chạy một lệnh riêng. Để minh họa, lệnh riêng biệt có thể là:echo 5 minutes complete

(Lưu ý: Tôi không muốn tiến trình hoàn thành lệnh, mà chỉ đơn giản là các lệnh được thực thi sau các khoảng thời gian được chỉ định.)

Có thể không?


1
Hầu hết thời gian, bạn không biết trước một quá trình sẽ mất bao lâu.
choroba

"Lệnh dựa trên thời gian" nghĩa là gì? Bạn có muốn tạo một thanh tiến trình? Dựa trên cụm từ hiện tại của câu hỏi của bạn, bạn có thể đặt lệnh chạy dài trong nền và sau đó hiển thị đồng hồ hệ thống. Vui lòng làm rõ.
tự đại diện

@Wildcard Tôi đã làm rõ trong câu hỏi. Không phải là một thanh tiến trình. Nó sẽ thực thi các lệnh sau một số khoảng thời gian
Aniket Bhattacharyea

1
"5 phút hoàn thành" là một điều kỳ lạ để lặp lại. Không phải "5 phút đã trôi qua"? Không phải "Thời gian là _____"? Bạn có muốn đảm bảo rằng một số khoảng thời gian xác định đã trôi qua kể từ khi lệnh chạy dài của bạn được bắt đầu, trước khi một lệnh tùy ý khác được chạy không? Nếu vậy, tại sao không chạy longcommand & sleep 300 && command-to-do-after-five-minutes? (Trên thực tế đó có lẽ là những gì bạn đang tìm kiếm.) Lưu ý rằng việc làm rõ của bạn là không đủ, vì bạn đã có hai triển khai thanh tiến trình đồng hồ ngay lập tức.
tự đại diện

Câu trả lời:


29

Chỉ cần chạy:

long-command & sleep 300; do-this-after-five-minutes

Các do-this-after-five-minutessẽ được chạy sau năm phút. Các long-commandsẽ được chạy ở chế độ nền.


10
Tôi thường sử dụng sleep 5m && foobar, vì vậy nếu tôi đổi ý và ^ C thì sleeplệnh tiếp theo sẽ không chạy.
Peter Cordes

@PeterCordes, khi tôi đã thử nghiệm nó với ví dụ sleep 3; ls^C, lệnh thứ hai không chạy. Không thực sự chắc chắn tại sao và có thể nó hoạt động khác nhau trong một vỏ không tương tác?
tự đại diện

1
@PeterCordes Không hoàn toàn - trừ khi nó khác nhau trên mỗi vỏ. Khi sleep 5m && echođang ngủ, khi bạn tạm ngưng, chỉ có sleeplệnh bị treo. Phần còn lại của dòng lệnh chạy, nhưng vì sleepbị đình chỉ, nó đã không thoát thành công và phần sau &&bị bỏ qua. Hãy thử đình chỉ sleep 5 || echo hellohellohiển thị trực tiếp sau khi nhấn ^Z.
hvd

1
@hvd: Yup, bạn đúng và tôi lại sai>. <, sử dụng bash4. Rõ ràng đã quá lâu kể từ khi tôi quyết định rằng && là cách để đi như một khu ổ chuột at(1), cho những thứ như sleep 30m && mplayer something.mp3lời nhắc nhở báo thức hoặc sleep 90m && fgđể tiếp tục một lệnh thâm dụng đĩa sau đó. Vì vậy, thực sự, sleep 5m && echo hellolà tốt vì ^Zđình chỉ sleepmà không chạy lệnh sau đây. Nếu bạn muốn có thể tạm dừng / tiếp tục toàn bộ lệnh ghép, ngay cả trước khi thoát khỏi chế độ ngủ, hãy sử dụng ( sleep 2 && echo hello ).
Peter Cordes

@hvd: Thành &&ngữ cho phép bạn hoàn toàn chắc chắn rằng bạn không giết tiến trình ngay sau khi ngủ chạy (vì bạn ^Zkhông thể chạy lệnh, thay vì mạo hiểm a ^C). Điều này rất hữu ích trong trường hợp sleep && fghoặc sleep && bgtrường hợp sử dụng, khi lệnh được tiếp tục là một phần thông qua một cái gì đó chậm.
Peter Cordes

5

Bạn có thể sử dụng tập lệnh này:

#!/bin/bash

TEMPFILE="$(mktemp)"
STARTTIME="$(date +%s)"
(./longprocess; rm -f "$TEMPFILE") &
while [ -f "$TEMPFILE" ]; do
    sleep 1s
    NOW="$(date +%s)"
    if (( (NOW-STARTTIME) % 300 == 0 )); then
        echo "$(( (NOW-STARTTIME)/60 )) minute(s) elapsed"
    fi
done
echo "Done!!!"

Nó thực thi của bạn longprocesstrong một sub-shellvà sau đó theo dõi tập tin 'khóa' được tạo trước đó để tồn tại.


2
Kiểm tra man bashcho SECONDS. Bạn có thể đặt SECONDS=0khi bắt đầu tập lệnh và chỉ kiểm tra mức lớn hơn hoặc bằng 300 hoặc đặt SECONDS=$((date +%s))và quên sử dụng datelại trong tập lệnh của mình ...

@yeti, cảm ơn vì gợi ý, tôi không biết điều đó.
Serge

@yeti, nếu bạn muốn dựa vào thời gian sau khi sleep 1sluôn luôn trễ hơn một giây so với trước đây sleep 1s... thì bạn đã trở thành nạn nhân của Sai lầm mà các lập trình viên tin về thời gian . (Mặc dù trong trường hợp này, bạn cũng có thể chỉ hiển thị thanh tiến trình đánh dấu băm hoặc một cái gì đó.)
Wildcard

@Wildcard ... Tôi hoàn toàn không đề cập đến sleep!

@yeti, đúng rồi bạn. Cảm ơn các mẹo về SECONDS! :)
tự đại diện

4

Có một lớp lót cho việc này:

( ( sleep $TIMEOUT ; echo "5 minutes complete") & $COMMAND )

Trong trường hợp của bạn TIMEOUT = 5m và LỰA CHỌN là lệnh dài.

Đồng thời xem câu trả lời của tôi cho bài đăng này Hết giờ với 'khởi động lại mạng dịch vụ'


Khởi chạy một lớp con ở phía trước và sau đó thực thi lệnh có vẻ phức tạp không cần thiết. Tôi sẽ loại bỏ các dấu ngoặc đơn bên ngoài và exec
glenn jackman

1
@glennjackman Bằng cách này, người ta có thể giết toàn bộ quy trình gửi CTRL + C (ví dụ) đến lớp vỏ chính (ngoài cùng).
coffeMug

1
Nhưng bằng cách sử dụng exec, bạn không có subshell nữa, bạn chỉ cần có lệnh. Cha mẹ của lệnh là shell chạy tập lệnh giống như bạn hoàn toàn không sử dụng một lớp con.
glenn jackman

3
#! /bin/bash

( sleep 4 ) & # <-- The long running process.

seconds=1
while jobs %1 &>/dev/null ; do
    echo $((seconds++)) seconds complete
    sleep 1    
done
echo Done.

jobs %1 thất bại một khi công việc% 1 đã dừng lại.

Lưu ý rằng trong thời gian dài hơn, $ giây có thể không đồng bộ với thời gian thực. Tốt hơn là lưu trữ thời gian bắt đầu và tính toán sự khác biệt với thời gian thực tế.

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.