Cách đơn giản để lệnh chạy trong 5 phút là gì? [bản sao]


66

Câu hỏi này đã có câu trả lời ở đây:

Có cách nào dễ dàng để cho một lệnh cụ thể (chỉ có thể kết thúc thông qua Ctrl-C) tự động chạy trong 5 phút không?

Ví dụ:

minute-command 5-minutes ping www.google.com

hoặc bất kỳ lệnh nào khác không tự chấm dứt.

Tôi muốn có thể chỉ định giới hạn thời gian, không chỉ 5 phút.

Câu trả lời:


67

Có (ít nhất) hai chương trình cung cấp chức năng này:

TÊN

timelimit - giới hạn hiệu quả thời gian thực hiện tuyệt đối của một quy trình

TÓM TẮC

timelimit [-pq] [-S killsig] [-s warnsig] [-T killtime] [-t warntime] command [arguments ...]

TÊN

timeout - chạy lệnh có giới hạn thời gian

TÓM TẮC

timeout [OPTION] DURATION COMMAND [ARG]...
timeout [OPTION]

Chúng được đóng gói như sau:

$ dlocate `which timeout timelimit`
timelimit: /usr/bin/timelimit
coreutils: /usr/bin/timeout

So sánh:

/-----------------------------+------------+----------------\
|            Feature          |  timelimit |     timeout    |
+=============================+============+================+
|   time to run               | -t time    | first argument |
+-----------------------------+------------+----------------+
|   terminate signal          | -s signal  | -s signal      |
+-----------------------------+------------+----------------+
|   grace period              | -T time    | -k time        |
+-----------------------------+------------+----------------+
|   kill signal               | -S signal  | (note 1)       |
+-----------------------------+------------+----------------+
|   propagate signals         | -p         | (note 2)       |
\-----------------------------+------------+----------------/

Ghi chú:

  1. timeoutluôn luôn sử dụng SIGKILLnhư là tín hiệu cuối cùng của nó.
  2. timeout không có bất kỳ chức năng nào để thoát với tín hiệu khi chương trình con làm như vậy.

Trạng thái thoát của hai chương trình khác nhau, nhưng thật khó để tóm tắt gọn gàng, vì vậy tôi khuyên bạn nên tự mình tham khảo các trang hướng dẫn sử dụng.

timeoutđược cài đặt trên nhiều hệ thống theo mặc định ( coreutilslà gói tiêu chuẩn trong nhiều bản phân phối), tôi khuyên bạn nên sử dụng trừ khi bạn cần các chức năng bổ sung được cung cấp bởi timelimit.


10
Tại sao bạn sẽ sử dụng cái này chứ không phải cái kia?
Brice M. Dempsey

2
@ BriceM.Dempsey Trên máy cục bộ của tôi, thời gian chờ là hiện tại, nhưng thời gian không có (mặc dù nó có sẵn từ repo). Vì vậy, nếu một trong số chúng được cài đặt sẵn ... Ngoài ra, chỉ cần nhìn vào chữ ký phương thức tôi có thể thấy rằng chúng làm những việc khác nhau và có các trường hợp sử dụng khác nhau.
Benubird

Lưu ý rằng có ít nhất hai triển khai timelimit. Xem Làm thế nào tôi có thể giết một quá trình và chắc chắn rằng PID chưa được sử dụng lại để biết thêm thông tin về chúng và thời gian chờ GNU.
sch

1
@ BriceM.Dempsey timeoutđược bao gồm trong GNU coreutils , timelimitkhông phải là. Bạn có thể đã cài đặt không, một hoặc cả hai. Đối với lần thứ hai, báo cáo thời gian thực hiện một lệnh và chấm dứt quá trình sinh ra sau một thời gian nhất định với một tín hiệu nhất định. Tín hiệu cảnh báo của người Viking được gửi trước , sau đó, sau khi hết thời gian, tín hiệu giết chết của người Viking, tương tự như cách init (8) hoạt động khi tắt máy. Vì vậy, ngay cả một sự khác biệt trong hành vi giữa .
Hastur

Vì lõi core GNU được cài đặt sẵn trên mọi GNU / Linux, timeoutlà cách để đi đến đó.
rexkogitans

87

Trên thực tế, đây là những gì timeoutdành cho:

TIMEOUT(1)                          User Commands                         TIMEOUT(1)

NAME
       timeout - run a command with a time limit

SYNOPSIS
       timeout [OPTION] DURATION COMMAND [ARG]...
       timeout [OPTION]

DESCRIPTION
       Start COMMAND, and kill it if still running after DURATION.

lx@lxtp:~$ dpkg -S /usr/bin/timeout
coreutils: /usr/bin/timeout

16

Được bashxây dựng nguyên chất , không có lõi

Tôi thấy rằng giải pháp này làm việc tại bashdựa vào một built-in lệnh mà không gọi một thực thi bên ngoài. Nó hoạt động trên hệ thống mà cuối cùng thậm chí không được cài đặt coreutils [ 1 ]

YourCommand & read -t 300 ;  kill $!                           # 1st version
YourCommand & read -t 300 || kill $!                           # 2nd version 

Giải thích : như bình thường khi bạn gửi một lệnh trong nền với &, PID của nó được lưu trữ trong các biến nội bộ $!(hiện diện trong phiên bản hiện đại của dash, csh, bash, tcsh, zsh...).
Điều gì thực sự làm cho sự khác biệt giữa các vỏ là sự hiện diện của các built-in lệnh read[ 2 ] và các tùy chọn -t. Trong phiên bản đầu tiên, nếu người dùng sẽ không hoàn thành một dòng đầu vào trước khi số giây được chỉ định, lệnh sẽ bị chấm dứt và mã trả về lỗi sẽ được tạo.

-t TIMEOUT Nguyên nhân đọc hết thời gian và trả về thất bại nếu một dòng đầu vào hoàn chỉnh không được đọc trong vòng TIMEOUT giây.

Phiên bản thứ hai hoạt động như phiên bản thứ 1 nhưng bạn có thể hủy bỏ thời gian chờ giết chỉ bằng cách nhấn enter.
Thật vậy, toán tử hoặc ||thực thi killcâu lệnh chỉ khi readlệnh thoát với mã trả về khác 0, khi hết thời gian chờ. Nếu bạn nhấn entertrước thời điểm đó, nó sẽ trả về 0 và nó sẽ không giết lệnh trước đó của bạn.


Giải pháp Coreutils [ 1 ]

Khi coreutils có mặt trên hệ thống của bạn và bạn không cần phải tiết kiệm thời gian và tài nguyên để gọi một chương trình bên ngoài, timeoutsleepcả hai đều là những cách hoàn hảo để đạt được mục tiêu của bạn.

timeoutViệc sử dụng timeoutlà đơn giản.
Cuối cùng, bạn có thể cân nhắc sử dụng -ktùy chọn để gửi tín hiệu tiêu diệt bổ sung nếu lần đầu tiên thất bại.

timeout 5m YourCommand                                         # 3rd version 

sleep Với sleepbạn có thể sử dụng tưởng tượng của bạn hoặc lấy một số cảm hứng [ 3 ] . Lưu ý rằng bạn có thể để lệnh của bạn ở chế độ nền hoặc ở nền trước (ví dụ: topthường cần phải ở phía trước).

YourCommand & sleep 5m; kill $!                                # 4th Background
YourCommand & pid=$! ; (sleep 5m; kill $pid;) &                # 5th Background

bash -c '(sleep 5m; kill $$) & exec YourCommand'               # 6th Foreground
(cmdpid=$BASHPID; (sleep 5m; kill $cmdpid) & exec YourCommand) # 7th Foreground

Giải thích

  • Trong phiên bản thứ 4, bạn thực hiện trong nền YourCommandsau đó shell của bạn sleeptrong 5 minuites. Khi nó được hoàn thành, quá trình nền cuối cùng ( $!) sẽ bị giết. Bạn dừng vỏ của bạn.
  • Trong phiên bản thứ 5 thay vì bạn thực thi trong nền YourCommandvà bạn lưu trữ ngay lập tức PID đó trong biến $pid. Sau đó, bạn thực hiện trong một giấc ngủ ngắn trong 5 phút và lệnh hệ quả của nó sẽ giết chết bộ lưu trữ đó. Vì bạn đã gửi nhóm lệnh này trong nền nên bạn không dừng trình bao của mình. Bạn cần lưu trữ PID trong một biến vì giá trị của $!có thể được cập nhật bằng cách thực hiện cuối cùng của một chương trình khác trong nền. Nói một cách đơn giản, bạn tránh được rủi ro để giết sai quy trình hoặc không có quy trình nào cả.
  • Trong phiên bản thứ 6, nó được gọi là bash shell mới sẽ tự sát sau 5 phút $$, sau đó nó được thực thi lệnh của bạn vẫn ở phía trước.
  • Trong phiên bản thứ 7, nó được gọi một lớp ()con lưu trữ PID của nó trong một biến ( cmdpid) và tự giết mình với một lớp con khác được gửi trong thực thi nền, sau đó chạy YourCommand ở phía trước.

Tất nhiên trong mỗi phiên bản, bạn có thể gửi tín hiệu tiêu diệt bạn cần, từ mức mặc định đến cực trị kill -9 , chỉ được sử dụng khi thực sự cần thiết.

Người giới thiệu

  • [ 1 ] Coreutils
  • [ 2 ] Hướng dẫn cho người mới bắt đầu Bash
  • [ 3 ] BashFAQ

2
"Với giấc ngủ, bạn có thể sử dụng trí tưởng tượng của mình hoặc lấy một số nguồn cảm hứng [liên kết đến Câu hỏi thường gặp của Bash]" +1 #thatsenoughiNETfortoday
joeytwiddle 3/03/2016

11

Đối với trường hợp cụ thể của bạn, hầu hết các triển khai pinghỗ trợ -choặc --countchấm dứt sau một số lần ping cụ thể:

ping -c 300 host.example.com

Đối với một giải pháp tổng quát hơn, xem các câu trả lời khác.


7
Tôi có ấn tượng OP chỉ cung cấp pingcho một ví dụ cụ thể. Anh ta không muốn một giải pháp theo từng trường hợp cho mọi chương trình khác nhau.
dùng1717828

8

Bạn có thể làm điều đó với một kịch bản đơn giản như thế này:

#!/bin/bash

#
# $1 is the time to let the program run, and $2, $3, ... are the command itself.
#

"${@:2}" &
PID=$!
sleep "${@:1:1}"
kill -2 $PID

(tín hiệu SIGINT = 2 được sử dụng theo đề xuất của Matija Nalis trong bình luận bên dưới).

Một lời giải thích về biểu thức bash (không phổ biến?) $@:...: Các tham số vị trí, ( $*, $@, "$*", "$@") thừa nhận thông số kỹ thuật bổ sung sau, ví dụ:

"${@:START:COUNT}"

có nghĩa là: trong tất cả các tham số, hãy lấy COUNT của chúng, tham số đầu tiên được thực hiện ở vị trí BẮT ĐẦU; nếu COUNT bị bỏ qua, hãy đưa tất cả chúng cho đến hết, bắt đầu với vị trí BẮT ĐẦU. Hãy nhớ rằng đó $0là tên chương trình. Nếu START là âm, hãy bắt đầu đếm từ cuối và nhớ rằng COUNT không thể âm, do đó, đối số cuối cùng là "${@:-1}". Ngoài ra, chỉ bao gồm luôn luôn bao gồm các tham số vị trí bên trong dấu ngoặc kép.


1
Có lẽ tôi sẽ thiết kế kịch bản để dành thời gian làm đối số đầu tiên hoặc cuối cùng và chạy tất cả các đối số khác làm lệnh. Để bash từ chia $1là khá thô. Ngoài ra, bạn có thể chỉ sleep "$1"hoặc một cái gì đó trong countdown.
Peter Cordes

1
@PeterCordes Xong, theo mong muốn của bạn.
MariusMatutiae

Thời gian trong đối số đầu tiên cho phép bạn thực hiện time=$1; shiftvà sau đó bạn không cần cú pháp cắt mảng cho các tham số vị trí. Nhưng vâng, điều đó đơn giản hơn nhiều.
Peter Cordes

1
@PeterCordes Đồng ý, nhưng bạn đã hỏi tôi xem liệu tôi có biết cách an toàn hơn để làm việc này không và tôi chỉ lười biếng, hoặc liệu tôi chỉ là người không biết gì. cười ngả nghiêng.
MariusMatutiae

như poster đã hỏi cụ thể về chương trình có thể bị gián đoạn ctrl-c, có lẽ tốt hơn nên thử kill -INTthay vì kill -9(hoặc ít nhất là -9chỉ thử sau vài giây nếu lần đầu tiên không thành công - nó mang lại cơ hội cho chương trình thoát khỏi sạch và không để lại các tệp tạm thời v.v.)
Matija Nalis

5

Vì bạn đề cập đến pingtrong ví dụ của bạn; lệnh này có một vài tùy chọn để dừng sau một khoảng thời gian cụ thể:

  • thời hạn w Chỉ định thời gian chờ, tính bằng giây, trước khi thoát ping bất kể có bao nhiêu gói đã được gửi hoặc nhận. Trong trường hợp này, ping không dừng sau khi gói đếm được gửi, nó chờ thời hạn hết hạn hoặc cho đến khi các đầu dò đếm được trả lời hoặc cho một số thông báo lỗi từ mạng.
  • Thời gian chờ W Thời gian chờ phản hồi, tính bằng giây. Tùy chọn chỉ ảnh hưởng đến thời gian chờ mà không có bất kỳ phản hồi nào, nếu không, ping sẽ đợi hai RTT.

-man ping

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.