एक "नींद" में बचे समय की मात्रा का निर्धारण कैसे करें?


11

मेरे पास है:

sleep 210m && for i in $(seq 1 5); do echo -e '\a'; sleep 0.5; done 

जब कुछ किया जाना चाहिए मुझे याद दिलाने के लिए एक सरल, नो-फ्रिल टाइमर के रूप में चल रहा है। वह sleep 210mपीआईडी ​​25347 है।

मैं यह पता लगाने की कोशिश कर रहा हूं कि नींद में कितना समय बचा है। मेरे साथ जो सबसे अच्छी नींद आई है, वह मूल नींद राशि (210 मिनट) में है:

$ echo "210 60 * $(ps -o etimes= 25347) - 60 ~ r n [:] P p" | dc
78:11

(स्पष्टीकरण: पहले बिट मूल नींद में सेकंड की संख्या की गणना करता है; $(ps…)बिट को सेकंड में नींद शुरू होने के बाद का समय मिलता है, फिर बाकी उन्हें घटाता है और मिनट और सेकंड में प्रदर्शित करता है।)

यह मेरे लिए होता है यह सामान्य रूप से उपयोगी होगा; क्या ऐसा करने के लिए इससे अच्छा तरीका है? या कम से कम एक चालाक तरीका नींद से समय को पार्स करने के लिए ps -o args?


1
ध्यान दें कि प्रक्रियाएं (और अक्सर कर सकती हैं) अपने जीवनकाल में एक से अधिक कमांड चलाती हैं। उदाहरण के लिए , sh -c 'sleep 1; sleep 2'कई shकार्यान्वयनों के साथ , यह वही प्रक्रिया है जो निष्पादित होती है shऔर बाद में निष्पादित होती है sleep 2(1 सेकंड बाद में)।
स्टीफन चेजलस

@ StéphaneChazelas मुझे नहीं लगता कि यहां ऐसा हो सकता है, संभवतः शेल केवल उस अंतिम कमांड पर अनुकूलन कर सकता है जो इसे निष्पादित कर रहा है (क्योंकि इसके बाद नियंत्रण हासिल करने का कोई तरीका नहीं है exec)। लेकिन यह किसी भी सामान्य समाधान के लिए एक अच्छा बिंदु है।
derobert

यह भी ध्यान दें कि कई गोले ( mkshऔर ksh93कम से कम) sleepबिल्ट-इन (तो शो-अप नहीं होंगे ps)।, आपको पहले से पता होना चाहिए कि sleepआप किन कार्यान्वयनों के साथ काम कर रहे हैं।
स्टीफन चेज़लस

जवाबों:


5

जीएनयू या सोलारिस 11 sleepतर्कों (एक या अधिक <double>[smhd]अवधि) का समर्थन करता है, इसलिए पारंपरिक कार्यान्वयन के साथ भी काम करेगा जो केवल एक दशमलव पूर्णांक संख्या (जैसे FreeBSD) का समर्थन करते हैं, लेकिन आईएसओ -860101 डेट्रायट जैसे अधिक जटिल तर्क को स्वीकार करने वालों के साथ नहीं )। etimeइसके बजाय इसका उपयोग करना etimesअधिक पोर्टेबल (मानक यूनिक्स) है।

remaining_sleep_time() { # arg: pid
  ps -o etime= -o args= -p "$1" | perl -MPOSIX -lane '
    %map = qw(d 86400 h 3600 m 60 s 1);
    $F[0] =~ /(\d+-)?(\d+:)?(\d+):(\d+)/;
    $t = -($4+60*($3+60*($2+24*$1)));
    for (@F[2..$#F]) {
      s/\?//g;
      ($n, $p) = strtod($_);
      $n *= $map{substr($_, -$p)} if $p;
      $t += $n
    }
    print $t'
}

( s/\?//gसे छुटकारा पाने के लिए है ?अक्षर है कि procps' psनियंत्रण वर्ण के लिए स्थानापन्न के रूप में उपयोग करता है। इसके बिना, यह पार्स करने के लिए विफल हो जाएगा sleep $'\r1d'या sleep $'\t1d'... दुर्भाग्य से, सहित कुछ स्थानों, में Cस्थान, इसे इस्तेमाल करता है .बजाय ?। ज्यादा हम क्या कर सकते हैं उस स्थिति में जैसा कि (आधे दिन) \t5dसे बताने का कोई तरीका नहीं है .5d

तर्क के रूप में पीआईडी ​​पास करें।

यह भी माना जाता है कि argv[0]पारित किए गए sleepमें रिक्त नहीं होते हैं और यह तर्क की संख्या काफी कम है कि यह छोटा नहीं है ps

उदाहरण:

$ sleep infinity & remaining_sleep_time "$!"
Inf
$ sleep 0xffp-6d &
$ remaining_sleep_time "$!"
344249
$ sleep 1m 1m 1m 1m 1m & remaining_sleep_time "$!"
300

[[[ddd-]HH:]MM:]SSकेवल सेकंड की संख्या के बजाय एक आउटपुट के लिए, इसके print $tसाथ बदलें :

$output = "";
for ([60,"%02d\n"],[60,"%02d:"],[24,"%02d:"],[inf,"%d-"]) {
  last unless $t;
  $output = sprintf($_->[1], $t % $_->[0]) . $output;
  $t = int($t / $_->[0])
}
printf "%s", $output;

1
0xffp-6d... अब, यह एक परीक्षण का मामला है! लेकिन असल में जीएनयू नींद चीजों की तरह लेता है sleep 1h 30mऔर साथ ही ...
derobert

@derobert। D'oh मैं शपथ ले सकता था कि मैंने कोशिश की थी। मुझे लगता है कि मैंने कोशिश की होगी sleep 1h -1mजो सोलारिस 11 पर काम करता है लेकिन जीएनयू के साथ नहीं sleep। ड्रॉइंग बोर्ड पर वापस। कम से कम यह ksh93 जैसे iso8601 अवधि का समर्थन नहीं करता है जो बहुत कठिन होगा।
स्टीफन चेज़लस 20

@derobert, कई तर्कों का समर्थन करने के लिए अपडेट किया गया
स्टीफन चेज़लस

@ StéphaneChazelas आपका समाधान अच्छा है, हालांकि यह उस स्थिति में काम नहीं करेगा जब इसे sleepरोक दिया जाए। यह इस मामले में नकारात्मक मूल्य भी प्रदर्शित कर सकता है।
भीड़

एक हफ्ते से इस जुर्माने का इस्तेमाल कर रहे थे लेकिन आज remaining_sleep_time 12838लौट आए -40642। यह @rush राज्यों के रूप में "रोकें" पर हो सकता है लेकिन यह सुनिश्चित नहीं होगा कि डिबग कैसे करें?
विनयुनुच्स

3

यह हल करने के लिए एक मजेदार समस्या की तरह लग रहा था; चूंकि थ्रिल ने एक पर्ल विकल्प को कवर किया है, यहां एक बैश स्क्रिप्ट है जो कुछ समान करता है। यह पर्याप्त त्रुटि-जांच नहीं करता है (यह मानता है कि आप एक नींद कमांड के वैध पीआईडी ​​में गुजर रहे हैं)। यह उसी सिंटैक्स को संभालता है जो GNU की कोरुटिल स्लीप करता है, अर्थात्:

  • s | m | h | d सेकंड / मिनट / घंटे / दिन के लिए प्रत्यय
  • कई बार पैरामीटर एक साथ जुड़ जाते हैं

#!/usr/bin/env bash

# input: PID of a sleep command
# output: seconds left in the sleep command

function parse_it_like_its_sleep {
  # $1 = one sleep parameter
  # print out the seconds it translates to

  mult=1
  [[ $1 =~ ([0-9][0-9]*)(s|m|h|d) ]] && {
    n=${BASH_REMATCH[1]}
    suffix=${BASH_REMATCH[2]}
  } || {
    n=$1
  }
  case $suffix in
    # no change for 's'
    (m) mult=60;;
    (h) mult=$((60 * 60));;
    (d) mult=$((60 * 60 * 24));;
  esac
  printf %d $((n * mult))
}

# TODO - some sanity-checking for $1
set -- $(ps -o etimes=,args= $1)
[[ $2 = "sleep" ]] || exit 1
elapsed=$1
shift 2
total=0
for arg
do
  # TODO - sanity-check $arg
  s=$(parse_it_like_its_sleep $arg)
  total=$((total + s))
done
printf "%d seconds left\n" $((total - elapsed))

भले ही GNU स्लीप तक सीमित हो (कुछ स्लीप इंप्लीमेंटेशन जैसे सोलारिस 11 या ksh93 बिलिन अधिक जटिल अवधि एक्सप्रेशन का समर्थन करते हैं), यह अधूरा है क्योंकि यह फ्लोटिंग पॉइंट नंबरों (जैसे sleep 0.5dया sleep 1e5या sleep infinity) के लिए काम नहीं करता है । bashZsh, ksh93 या यश जैसे फ्लोटिंग पॉइंट्स को सपोर्ट करने वाले शेल से स्विच करने से मदद मिलेगी। ऐसा नहीं है कि etimesपोर्टेबल नहीं है।
स्टीफन चेज़लस

फ़्लोटिंग फ़्लोटिंग पॉइंट के लिए खरगोश का छेद जितना मैं जाना चाहता था उससे अधिक गहरा गया, इसलिए मैं इसे ज्ञात सीमाओं के साथ यहाँ छोड़ सकता हूँ, और यह तथ्य कि यह ओपी के सुझाव पर मामूली सुधार है (यह पीआईडी ​​से नींद का समय निर्धारित कर सकता है) बनाम हार्ड-कोडिंग कि में)।
जेफ स्कालर


1

यह एक स्क्रिप्ट के साथ बेहतर किया जा सकता है जो एक QUIT(आमतौर पर control+\) या INFOसिग्नल के साथ संबंध होने पर शेष समय दिखा सकता है ।

#!/usr/bin/env perl
#
# snooze - sleep for a given duration, with SIGINFO or SIGQUIT
# (control+\ typically) showing how much time remains. Usage:
#
#   snooze 3m; make-noise-somehow
#
# or with
#
#   snooze 25m bread; make-noise-somehow
#
# one can then elsewhere
#
#   pkill -INFO snooze-bread

use strict;
use warnings;
use Term::ReadKey qw(ReadMode);

my %factors = ( s => 1, m => 60, h => 3600, d => 86400 );

my $arg = shift or die "Usage: $0 sleep-time [label]\n";
my $to_sleep = 0;
while ( $arg =~ m/([0-9]+)([smhd])?/g ) {
    my $value  = $1;
    my $factor = $2;
    $value *= $factors{$factor} if $factor;
    $to_sleep += $value;
}
die "nothing to die to sleep to sleep no more for\n" if $to_sleep == 0;

my $label = shift;
$0 = $label ? "snooze-$label" : "snooze";

ReadMode 2;    # noecho to hide control+\s from gunking up the message

sub remainder { warn "$0: " . deltatimefmt($to_sleep) . " remaining\n" }

sub restore {
    ReadMode 0;
    warn "$0: " . deltatimefmt($to_sleep) . " remainds\n";
    exit 1;
}

# expect user to mash on control+\ or whatever generates SIGINFO
for my $name (qw/ALRM INFO QUIT/) {
    $SIG{$name} = \&remainder;
}

# back to original term settings if get blown away
for my $name (qw/HUP INT TERM USR1 USR2/) {
    $SIG{$name} = \&restore;
}

$SIG{TSTP} = 'IGNORE';    # no Zees for you!

while ( $to_sleep > 0 ) {
    $to_sleep -= sleep $to_sleep;
}

ReadMode 0;
exit;

sub deltatimefmt {
    my $difference = shift;

    return "0s" if $difference == 0;

    my $seconds = $difference % 60;
    $difference = ( $difference - $seconds ) / 60;
    my $minutes = $difference % 60;
    $difference = ( $difference - $minutes ) / 60;

    #  my $hours = $difference;
    my $hours = $difference % 24;
    $difference = ( $difference - $hours ) / 24;
    my $days  = $difference % 7;
    my $weeks = ( $difference - $days ) / 7;

    # better way to do this?
    my $temp = ($weeks) ? "${weeks}w " : q{};
    $temp .= ($days)    ? "${days}d "    : q{};
    $temp .= ($hours)   ? "${hours}h "   : q{};
    $temp .= ($minutes) ? "${minutes}m " : q{};
    $temp .= ($seconds) ? "${seconds}s"  : q{};
    return $temp;
}

वास्तव में सवाल का जवाब नहीं देता (क्योंकि मेरी नींद पहले से ही चल रही थी) -लेकिन भविष्य में इससे बचना है, इसलिए अभी भी उपयोगी है। आश्चर्य है कि अगर एक टर्मिनल उलटी गिनती अलार्म उपयोगिता कहीं है ...
derobert

यह भी देखें zshकी schedऔर atएक और दृष्टिकोण है कि समय से क्वेरी की अनुमति देता है के लिए आदेश।
स्टीफन चेजलस

0

Tqdm अजगर मॉड्यूल के साथ काफी आसान होना चाहिए।

एक अच्छा दृश्य प्रगति बार दिखाता है और इसे यूनिक्स पाइप के रूप में इस्तेमाल किया जा सकता है।

https://pypi.python.org/pypi/tqdm

निम्नलिखित अजगर स्निपेट 100 सेकंड गिना जाता है

import time
from tqdm import tqdm
for i in tqdm(range(100)):
    time.sleep(1)

55% | ██████████ | 55/100 [00:55 <00:45, 1.00s / यह]


मैं यह नहीं देखता कि उस पृष्ठ को देखना कितना आसान होगा (हालाँकि मैं पायथन प्रोग्रामर नहीं हूँ)। आपको लगता है कि मन में कुछ है - कृपया इसे अपने उत्तर में जोड़ें।
derobert
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.