GNU/Linux >> Znalost Linux >  >> Linux

Časový limit ve skriptu Shell?

Mám shell skript to je čtení ze standardního vstupu . Ve výjimečných případech nebude nikdo připraven poskytnout vstup a skript musí vyčerpat časový limit . V případě vypršení časového limitu musí skript provést nějaký čistící kód. Jaký je nejlepší způsob, jak to udělat?

Tento skript musí být velmi přenosný , včetně unixových systémů 20. století bez kompilátoru C a vestavěných zařízení s busyboxem, takže na Perl, bash, jakýkoli kompilovaný jazyk a dokonce i plný POSIX.2 se nelze spolehnout. Konkrétně $PPID , read -t a pasti dokonale vyhovující POSIX nejsou k dispozici. Zápis do dočasného souboru je také vyloučen; skript se může spustit, i když jsou všechny souborové systémy připojeny pouze pro čtení.

Aby to bylo složitější, chci také, aby byl scénář přiměřeně rychlý když to nevyprší. Konkrétně skript používám také ve Windows (hlavně v Cygwinu), kde jsou fork a exec obzvlášť nízké, takže jejich použití chci omezit na minimum.

Stručně řečeno, mám

trap cleanup 1 2 3 15
foo=`cat`

a chci přidat časový limit. Nemohu nahradit cat s read vestavěný. V případě vypršení časového limitu chci provést cleanup funkce.

Pozadí:Tento skript hádá kódování terminálu vytištěním několika 8bitových znaků a porovnáním pozice kurzoru před a za. Začátek skriptu testuje, že je stdout připojen k podporovanému terminálu, ale někdy prostředí lže (např. plink nastaví TERM=xterm i když je volána s TERM=dumb ). Příslušná část skriptu vypadá takto:

text='Éé'  # UTF-8; shows up as Ãé on a latin1 terminal
csi='␛['; dsr_cpr="${csi}6n"; dsr_ok="${csi}5n"  # ␛ is an escape character
stty_save=`stty -g`
cleanup () { stty "$stty_save"; }
trap 'cleanup; exit 120' 0 1 2 3 15     # cleanup code
stty eol 0 eof n -echo                # Input will end with `0n`
# echo-n is a function that outputs its argument without a newline
echo-n "$dsr_cpr$dsr_ok"              # Ask the terminal to report the cursor position
initial_report=`tr -dc ;0123456789`  # Expect ␛[42;10R␛[0n for y=42,x=10
echo-n "$text$dsr_cpr$dsr_ok"
final_report=`tr -dc ;0123456789`
cleanup
# Compute and return initial_x - final_x

Jak mohu upravit skript tak, že pokud tr nepřečetl žádný vstup po 2 sekundách, je zabit a skript provede cleanup funkce?

Přijatá odpověď:

Co s tím:

foo=`{ { cat 1>&3; kill 0; } | { sleep 2; kill 0; } } 3>&1`

To znamená:spusťte příkaz produkující výstup a sleep ve stejné skupině procesů, skupině procesů jen pro ně. Kterýkoli příkaz vrátí jako první, zabije celou skupinu procesů.

Divil by se někdo:Ano, trubka se nepoužívá; obchází se pomocí přesměrování. Jediným účelem je, aby shell spouštěl dva procesy ve stejné skupině procesů.

Související:Zdá se, že skript pro zmenšení a kompresi diskových obrazů DMG v tomto scénáři nefunguje dobře?

Jak Gilles zdůraznil ve svém komentáři, toto nebude fungovat ve skriptu shellu, protože proces skriptu by byl zabit spolu se dvěma podprocesy.

Jedním ze způsobů¹, jak vynutit spuštění příkazu v samostatné skupině procesů, je spustit nový interaktivní shell:

#!/bin/sh
foo=`sh -ic '{ cat 1>&3; kill 0; } | { sleep 2; kill 0; }' 3>&1 2>/dev/null`
[ -n "$foo" ] && echo got: "$foo" || echo timeouted

Ale s tím mohou existovat výhrady (např. když stdin není tty?). Přesměrování stderr slouží k odstranění zprávy „Ukončeno“, když je interaktivní shell zabit.

Testováno pomocí zsh ,bash a dash . Ale co oldies?

B98 navrhuje následující změnu fungující na Mac OS X s GNU bash 3.2.57 nebo Linux s pomlčkou:

foo=`sh -ic 'exec 3>&1 2>/dev/null; { cat 1>&3; kill 0; } | { sleep 2; kill 0; }'`



Linux
  1. Určit prostředí ve skriptu za běhu?

  2. Určení cesty ke zdrojovému skriptu Shell?

  3. Neočekávané chování skriptu Shell?

  1. Jak vytvořit dočasný soubor ve skriptu Shell?

  2. Skrýváte heslo ve skriptech Shell?

  3. Význam $? Ve skriptu Shell?

  1. Shell Script pro tisk pyramidy hvězd

  2. Paralelní spuštění skriptu shellu

  3. Aktuální adresář skriptu Shell?