วิธีการกำหนดระยะเวลาที่เหลือใน“ การนอนหลับ”?


11

ฉันมี:

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

ทำงานเป็นตัวจับเวลาแบบเรียบง่ายไม่สะดุดเพื่อเตือนฉันเมื่อมีบางสิ่งที่ควรทำ นั่นsleep 210mคือ PID 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

นอกจากนี้โปรดทราบว่ามีเชลล์หลายตัว ( mkshและksh93อย่างน้อย) ที่มีsleepอยู่แล้วภายใน (ดังนั้นจะไม่แสดงในps) คุณต้องทราบล่วงหน้าว่าsleepการใช้งานใดที่คุณต้องเผชิญ
Stéphane Chazelas

คำตอบ:


5

สนับสนุน GNU หรือ Solaris 11 sleepข้อโต้แย้ง (หนึ่งหรือมากกว่า<double>[smhd]ระยะเวลาดังนั้นก็จะทำงานร่วมกับการใช้งานแบบดั้งเดิมที่มีการสนับสนุนเพียงหนึ่งเลขทศนิยมจำนวนเต็ม (เช่นเดียวกับ FreeBSD) แต่ไม่ได้อยู่กับผู้ที่ยอมรับข้อโต้แย้งที่ซับซ้อนมากขึ้นเช่นISO-8601 ระยะเวลา ) ใช้etimeแทนetimesแบบพกพาที่มากกว่า (มาตรฐาน Unix)

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 (ครึ่งวัน))

ส่ง pid เป็นอาร์กิวเมนต์

ที่ยังอนุมานargv[0]ส่งผ่านไปยังไม่ได้มีช่องว่างและจำนวนของการขัดแย้งก็พอขนาดเล็กที่ยังไม่ได้ตัดทอนโดยsleepps

ตัวอย่าง:

$ 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... ตอนนี้เป็นกรณีทดสอบ! แต่ที่จริงแล้วการนอนหลับของ GNU นั้นจะทำสิ่งต่าง ๆ เช่นsleep 1h 30mกัน ...
Derobert

derobert @ โอ้ฉันสาบานได้แล้วว่าฉันจะลองมัน ผมคิดว่าผมจะต้องมีความพยายามsleep 1h -1mที่ทำงานบน Solaris 11 แต่ไม่ได้มี sleepGNU กลับไปที่กระดานวาดภาพ อย่างน้อยก็ไม่รองรับระยะเวลา iso8601 เช่น ksh93 ซึ่งจะยากกว่านี้มาก
Stéphane Chazelas

@derobert ได้รับการอัปเดตเพื่อรองรับอาร์กิวเมนต์หลายข้อ
Stéphane Chazelas

@ StéphaneChazelasทางออกของคุณดีแม้ว่ามันจะไม่ทำงานในกรณีsleepที่หยุดชั่วคราว มันอาจแสดงค่าลบในกรณีนี้
เร่ง

ได้ใช้ดีนี้เป็นสัปดาห์ แต่วันนี้กลับมาremaining_sleep_time 12838 -40642อาจเป็น "หยุดชั่วคราว" เนื่องจากสถานะ @rush แต่ไม่แน่ใจว่าจะแก้ปัญหาอย่างไร
WinEunuuchs2Unix

3

ดูเหมือนว่าจะเป็นปัญหาที่สนุกในการแก้ เนื่องจาก thrig ครอบคลุมตัวเลือก Perl นี่คือสคริปต์ทุบตีที่ทำสิ่งที่คล้ายกัน การตรวจสอบข้อผิดพลาดไม่เพียงพอ (ถือว่าคุณผ่าน PID ที่ถูกต้องของคำสั่ง sleep) มันจัดการกับไวยากรณ์เดียวกับที่coreutils ของ GNU 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 นอนหลับ (บางคนนอนหลับการใช้งานเช่น Solaris 11 หรือ ksh93 สนับสนุน builtin ที่ซับซ้อนมากขึ้นในช่วงระยะเวลาการแสดงออก) ที่ไม่สมบูรณ์ขณะที่มันไม่ทำงานสำหรับตัวเลขทศนิยม (ชอบsleep 0.5dหรือsleep 1e5หรือsleep infinity) การเปลี่ยนจากbashเป็นเชลล์ที่สนับสนุนคะแนนลอยตัวเช่น zsh, 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

ดูเพิ่มเติมzsh's schedและatคำสั่งสำหรับวิธีการที่ช่วยให้การสอบถามเวลาอีก
Stéphane Chazelas

0

ควรง่ายพอกับโมดูล tqdm python

แสดงแถบความคืบหน้าของภาพที่ดีและสามารถใช้เป็นไพพ์ unix

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 / it]


ฉันไม่เห็นว่ามันจะง่ายจากการดูที่หน้า (แม้ว่าฉันไม่ใช่โปรแกรมเมอร์ Python) คุณมีบางสิ่งในใจ - โปรดเพิ่มไปยังคำตอบของคุณ
Derobert
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.