"수면"에 남은 시간을 결정하는 방법은 무엇입니까?


11

나는 가지고있다:

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

간단한 작업이 필요없는 타이머로 실행하면 무언가를해야 할 때를 상기시켜줍니다. 즉 sleep 210mPID 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éphane Chazelas

@ StéphaneChazelas 나는 여기서 일어날 수 있다고 생각하지 않습니다. 아마도 쉘은 마지막으로 실행중인 명령에 대해서만 최적화를 수행 할 수 있다고 생각합니다 ( exec. 그러나 그것은 일반적인 솔루션에 대한 좋은 지적입니다.
derobert

또한 여러 셸 ( mkshksh93최소한)이 sleep내장되어 있으므로 (에 표시되지 않음 ps) sleep처리중인 구현을 미리 알아야 합니다.
Stéphane Chazelas

답변:


5

GNU 또는 Solaris 11 sleep인수를 지원합니다 (하나 이상의 <double>[smhd]지속 기간이므로 하나의 10 진수 정수 (FreeBSD와 같이) 만 지원하지만 ISO-8601 지속 기간 과 같은 더 복잡한 인수를 허용하지 않는 기존 구현에서는 작동합니다 ). 사용 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로케일이 사용하는 .대신 ?. 많은 우리가 할 수있는 것은 아닙니다 이 경우에을 알 수있는 방법이 없기 때문에 \t5dA로부터 .5d) (반나절).

pid를 인수로 전달하십시오.

또한 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

A의 [[[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... 이제 테스트 사례입니다! 그러나 실제로 GNU 수면은 다음과 같은 것들을 필요 sleep 1h 30m로합니다.
derobert

@derobert. 내가 맹세했을 수 있습니다. sleep 1h -1mSolaris 11에서는 작동하지만 GNU에서는 작동하지 않아야한다고 생각합니다.sleep . 드로잉 보드로 돌아갑니다. 적어도 ksh93과 같은 iso8601 지속 시간을 지원하지 않으므로 훨씬 더 어려울 것입니다.
Stéphane Chazelas

@derobert, 여러 가지 주장을 지원하기 위해 업데이트
Stéphane Chazelas

@ StéphaneChazelas 솔루션이 훌륭하지만 sleep일시 중지 된 경우에는 작동하지 않습니다 . 이 경우 음수 값을 표시 할 수도 있습니다.
돌진

일주일 동안이 벌금을 사용했지만 오늘 remaining_sleep_time 12838돌아왔다 -40642. @rush 상태로 "일시 중지"상태 일 수 있지만 디버깅 방법을 잘 모르십니까?
WinEunuuchs2Unix

3

이것은 해결하기에 재미있는 문제처럼 보였다. thrig가 perl 옵션을 다루었으므로 비슷한 것을 수행하는 bash 스크립트가 있습니다. 충분한 오류 검사를 수행하지 않습니다 (유휴 명령의 유효한 PID를 전달한다고 가정). GNU의 coreutils sleep 과 동일한 구문 , 즉 다음을 처리합니다 .

  • 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 1e5sleep infinity). bashzsh, ksh93 또는 yash와 같은 부동 소수점을 지원하는 쉘로 전환 하면 도움이됩니다. 아니 그 etimes이식 할 수 없습니다.
Stéphane Chazelas

부동 소수점을 파싱하기위한 토끼 구멍은 내가 갈 수있는 것보다 깊어 졌으므로 알려진 제한 사항으로 여기를 남겨 둘 수 있으며 OP의 제안에 비해 약간의 개선 사항 일뿐입니다 (PID에서 수면 시간을 결정할 수 있음) 대 하드 코딩).
Jeff Schaller


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

시간 쿼리를 허용하는 다른 접근 방법은 zshschedat명령을 참조하십시오 .
Stéphane Chazelas

0

tqdm python 모듈로 충분히 쉬워야합니다.

멋진 시각적 진행률 표시 줄을 표시하고 유닉스 파이프로 사용할 수 있습니다.

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.00 초 / it]


나는 그 페이지를 보는 것이 얼마나 쉬운 지 알지 못한다 (파이썬 프로그래머는 아니지만). 생각이있는 것 같습니다. 답변에 추가하십시오.
derobert
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.