GNU/Linux >> LINUX-Kenntnisse >  >> Linux

Zeitüberschreitung in einem Shell-Skript?

Ich habe ein Shell-Skript das ist das Lesen von der Standardeingabe . In seltenen Fällen ist niemand bereit, Eingaben zu machen, und das Skript muss eine Zeitüberschreitung aufweisen . Im Falle einer Zeitüberschreitung muss das Skript einen Bereinigungscode ausführen. Wie geht das am besten?

Dieses Skript muss sehr portabel sein , einschließlich für Unix-Systeme des 20. Jahrhunderts ohne C-Compiler und für eingebettete Geräte, auf denen Busybox ausgeführt wird, sodass Perl, Bash, jede kompilierte Sprache und sogar das vollständige POSIX.2 nicht zuverlässig sind. Insbesondere $PPID , read -t und perfekt POSIX-konforme Fallen sind nicht verfügbar. Auch das Schreiben in eine temporäre Datei ist ausgeschlossen; Das Skript kann auch dann ausgeführt werden, wenn alle Dateisysteme schreibgeschützt gemountet sind.

Um die Sache noch schwieriger zu machen, möchte ich auch, dass das Skript einigermaßen schnell ist wenn es nicht abläuft. Insbesondere verwende ich das Skript auch unter Windows (hauptsächlich in Cygwin), wo fork und exec besonders niedrig sind, sodass ich deren Verwendung auf ein Minimum beschränken möchte.

Kurz gesagt, ich habe

trap cleanup 1 2 3 15
foo=`cat`

und ich möchte ein Timeout hinzufügen. Ich kann cat nicht ersetzen mit dem read eingebaut. Im Falle einer Zeitüberschreitung möchte ich die cleanup ausführen Funktion.

Hintergrund:Dieses Skript errät die Codierung des Terminals, indem es einige 8-Bit-Zeichen ausgibt und die Cursorposition davor und danach vergleicht. Der Anfang des Skripts testet, dass stdout mit einem unterstützten Terminal verbunden ist, aber manchmal lügt die Umgebung (z. B. plink setzt TERM=xterm auch wenn es mit TERM=dumb aufgerufen wird ). Der relevante Teil des Skripts sieht folgendermaßen aus:

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

Wie kann ich das Skript so ändern, dass wenn tr nach 2 Sekunden keine Eingabe gelesen hat, wird es beendet und das Skript führt die cleanup aus Funktion?

Akzeptierte Antwort:

Was ist damit:

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

Das heißt:Führen Sie den ausgabeerzeugenden Befehl aus und sleep in der gleichen Prozessgruppe, eine Prozessgruppe nur für sie. Welcher Befehl zuerst zurückkehrt, beendet die gesamte Prozessgruppe.

Würde sich jemand fragen:Ja, das Rohr wird nicht verwendet; Es wird mit den Umleitungen umgangen. Der einzige Zweck davon ist, dass die Shell die beiden Prozesse in derselben Prozessgruppe ausführt.

Verwandte:Ein Skript zum Verkleinern und Komprimieren von DMG-Festplattenabbildern scheint in dem Szenario nicht gut zu funktionieren?

Wie Gilles in seinem Kommentar betonte, funktioniert dies in einem Shell-Skript nicht, da der Skriptprozess zusammen mit den beiden Unterprozessen beendet würde.

Eine Möglichkeit¹, die Ausführung eines Befehls in einer separaten Prozessgruppe zu erzwingen, besteht darin, eine neue interaktive Shell zu starten:

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

Dabei kann es jedoch zu Einschränkungen kommen (z. B. wenn stdin kein tty ist?). Die stderr-Umleitung ist da, um die „Beendet“-Nachricht loszuwerden, wenn die interaktive Shell beendet wird.

Getestet mit zsh ,bash und dash . Aber was ist mit Oldies?

B98 schlägt die folgende Änderung vor, die unter Mac OS X mit GNU bash 3.2.57 oder Linux mit Bindestrich funktioniert:

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



Linux
  1. Shell im Script zur Laufzeit ermitteln?

  2. Unerwartetes Verhalten eines Shell-Skripts?

  3. Wie erstelle ich eine temporäre Datei im Shell-Skript?

  4. Passwort in Shell-Skripten verstecken?

  5. Shell-Skript zum Drucken der Sternenpyramide

So verwenden Sie Variablen in Shell-Skripten

So erstellen Sie Shell-Skripte

Wie führe ich einen Befehl in einem Shell-Skript aus?

Transliterationsskript für die Linux-Shell

Kann eine .sh-Datei Malware sein?

Shell zur Laufzeit im Skript ermitteln