Bir "uykuda" kalan süre nasıl belirlenir?


11

Sahibim:

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

bir şeylerin ne zaman yapılması gerektiğini hatırlatmak için basit, fırfırsız bir zamanlayıcı olarak çalışıyor. Bu sleep 210mPID 25347.

Uykuda ne kadar zaman kaldığını anlamaya çalışıyorum. Geldiğim en iyi şey, orijinal uyku miktarını (210 dakika) koymakla birlikte:

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

(Açıklama: İlk bit, orijinal uykudaki saniye sayısını hesaplar; $(ps…)bit, uykunun saniye olarak başlamasından bu yana geçen süreyi alır, geri kalanı bunları çıkarır ve dakika ve saniye olarak görüntüler.)

Bana göre bu genel olarak yararlı olur; Bunu yapmanın daha iyi bir yolu var mı? Ya da en azından uyku zamanını ayrıştırmanın akıllıca bir yolu ps -o argsmu?


1
İşlemlerin ömürleri boyunca birden fazla komut çalıştırabileceğini (ve çoğu zaman çalıştırabileceğini) unutmayın. Örneğin sh -c 'sleep 1; sleep 2', birçok shuygulamada, yürütme shve daha sonra yürütme ile aynı işlemdir sleep 2(1 saniye sonra).
Stéphane Chazelas

@ StéphaneChazelas Burada olabileceğini düşünmüyorum, muhtemelen kabuk bu optimizasyonu sadece yürüttüğü son komutta yapabilir (daha sonra kontrolü tekrar kazanmanın bir yolu olmadığı için exec). Ancak bu, herhangi bir genel çözüm için iyi bir nokta.
derobert

Ayrıca, birkaç merminin ( mkshve ksh93en azından) sleepyerleşik olduğunu (bu yüzden görünmeyeceğini ps) unutmayın. Önceden hangi sleepuygulamalarla uğraştığınızı bilmeniz gerekir .
Stéphane Chazelas

Yanıtlar:


5

GNU veya Solaris 11 sleepargümanlarını destekleme (bir veya daha fazla <double>[smhd]süre, bu nedenle yalnızca bir ondalık tam sayı sayısını (FreeBSD'de olduğu gibi) destekleyen, ancak ISO-8601 süreleri gibi daha karmaşık argümanları kabul edenlerle değil, geleneksel uygulamalarla da çalışır . Bu daha taşınabilir (standart Unix) etimeyerine kullanmak 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/\?//gkurtulmak için ise ?karakterlerin olduğu procps' psdenetleme karakterleri yerine kullanımları. Onsuz ayrıştırmak için başarısız olur sleep $'\r1d'veya sleep $'\t1d'Maalesef dahil olmak üzere bazı yerellerde ... Clocale, kullandığı .yerine ?. çok yapabileceğimiz Değil bu durumda \t5dbir .5d(yarım gün) ' den anlamanın bir yolu olmadığından ).

Pid'i bağımsız değişken olarak iletin.

Bu, argv[0]iletilen sleepöğenin boşluk içermediğini ve argüman sayısının kesilmeyecek kadar küçük olduğunu varsayar ps.

Örnekler:

$ 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:]SSSadece saniye sayısı yerine bir çıktı için şunu kullanın 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... Şimdi, bu bir test vakası! Ama aslında GNU uykusu da benzer şeyleri alıyor sleep 1h 30m...
derobert

@derobert. Bunu denediğime yemin edebilirdim. Sanırım sleep 1h -1mSolaris 11 üzerinde çalışan ancak GNU ile olmayanları denemeliydim sleep. Çizim tahtasına geri dön. En azından ksh93 gibi daha zor olan iso8601 sürelerini desteklemiyor.
Stéphane Chazelas

@derobert, birkaç argümanı destekleyecek şekilde güncellendi
Stéphane Chazelas

@ StéphaneChazelas çözümünüz iyi, ancak sleepduraklama durumunda işe yaramaz . Bu durumda negatif değer bile gösterebilir.
acele

Bu para cezası bir haftadır kullanılıyor ama bugün remaining_sleep_time 12838geri döndü -40642. @Rush gibi "Duraklat" olabilir ama nasıl hata ayıklamak için emin değil misiniz?
WinEunuuchs2Unix

3

Bu çözülmesi eğlenceli bir sorun gibi görünüyordu; Thrig perl seçeneğini kapsadığından, benzer bir şey yapan bir bash betiği. Yeterli hata denetimi yapmaz (uyku komutunun geçerli bir PID'sini geçtiğinizi varsayar). GNU'nun coreutils uykusuyla aynı sözdizimini işler :

  • s | m | h | d saniye / dakika / saat / gün için son ekler
  • çoklu zaman parametreleri bir araya getirilir

#!/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 uyku ile sınırlı olsa bile (Solaris 11 veya ksh93 yerleşik gibi bazı uyku uygulamaları çok daha karmaşık süre ifadelerini destekler), kayan nokta sayıları ( sleep 0.5dveya sleep 1e5veya sleep infinity) için çalışmadığından bu tamamlanmamıştır . bashZsh, ksh93 veya yash gibi kayan noktaları destekleyen bir mermiye geçmek yardımcı olacaktır. Bu etimestaşınabilir değil.
Stéphane Chazelas

Kayan noktayı ayrıştırmak için tavşan deliği gitmeye istekli olduğumdan daha derine gitti, bu yüzden bunu burada bilinen sınırlamalar ile bırakabilirim ve bunun OP'nin önerisine göre sadece küçük bir gelişme (PID'den uyku süresini belirleyebilir) sabit kodlamaya karşı).
Jeff Schaller


1

Bu, bir QUIT(genellikle control+\) veya INFOsinyalle bağlandığında kalan süreyi gösterebilen bir komut dosyasıyla daha iyi yapılabilir .

#!/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;
}

Soruyu gerçekten cevaplamıyor (uykum zaten çalıştığı için) - ama gelecekte bundan kaçınıyor, bu yüzden hala kullanışlı. Bir yerde bir terminal geri sayım alarm programı olup olmadığını merak ediyorum ...
derobert

Ayrıca bkz. zsh'S schedve atzamanı sorgulamaya izin veren başka bir yaklaşım için komut.
Stéphane Chazelas

0

Tqdm python modülü ile yeterince kolay olmalıdır.

Güzel bir görsel ilerleme çubuğu gösterir ve bir unix borusu olarak kullanılabilir.

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

Aşağıdaki python snippet'i 100 saniye sayıyor

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

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


Bu sayfaya bakmanın ne kadar kolay olacağını görmüyorum (Python programcısı olmamasına rağmen). Aklınızda bir şey var gibi görünüyor - lütfen cevabınıza ekleyin.
derobert
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.