goer@ellis.uchicago.edu (Richard L. Goerwitz) (05/26/91)
Is there any elegant way to achive a timeout on a read within a shell script? Perhaps even "fairly elegant" would do. Even a kludge? -- -Richard L. Goerwitz goer%sophist@uchicago.bitnet goer@sophist.uchicago.edu rutgers!oddjob!gide!sophist!goer
heinz@cc.univie.ac.at (05/27/91)
In <1991May26.165314.21533@midway.uchicago.edu> goer@ellis.uchicago.edu (Richard L. Goerwitz) writes: >Is there any elegant way to achive a timeout on a read within >a shell script? Perhaps even "fairly elegant" would do. Even >a kludge? >-- > -Richard L. Goerwitz goer%sophist@uchicago.bitnet > goer@sophist.uchicago.edu rutgers!oddjob!gide!sophist!goer Here is a quick 'n' dirty hack. I'm quite sure there are more elegant solutions, but this is the first that came into my mind. ----- Start of sample script ----- #! /bin/sh -- trap ":" 2 (sleep 1; kill -2 $$) & read input trap 2 echo End of script ----- End of sample script ----- Explanation: 1) Use the Bourne Shell as interpreter (you may use any other shell as well). 2) The empty command (:) is associated with signal number 2. You may use any other signal as well, barring signal 9. You may also associate any other command with the signal, like trap "echo Ouch! That hurt!" 2 In the above script, no action needs to be performed upon receipt of the signal, so the empty command is used. You can't use empty quotes, since this would mean to ignore the signal, which would be wrong here. 3) A subshell is started in the background, which performs the following actions: a) sleep 1 second (insert your timeout here); b) send signal number 2 to the parent shell ($$ is expanded to the PID of the shell executing the script) after waking up from the sleep. 4) Meanwhile, the 'main' shell executes the read (and, of course, blocks waiting for input). Upon receipt of the signal from the background process, it interrupts the read, executes the action associated with the signal in the trap statement (which is nothing in this example), and continues execution of the script. 5) In case you have to, reset the action for the signal you used to the default action. 6) Continue with your script. Hope this helps. I'd appreciate it if someone posted a more elegant solution (without sub-processes and stuff like that :) Greetings, HH -- -------------------------------------------------------------------------------- ---/ Heinz M. Herbeck / Trust me, I know / /- --/ heinz@sophie.pri.univie.ac.at / what I'm doing ! / /-- -/ Vienna University, Austria / (Sledge Hammer) / /--- --------------------------------------------------------------------------------
martin@mwtech.UUCP (Martin Weitzel) (05/27/91)
In article <1991May26.165314.21533@midway.uchicago.edu> goer@ellis.uchicago.edu (Richard L. Goerwitz) writes: >Is there any elegant way to achive a timeout on a read within >a shell script? Perhaps even "fairly elegant" would do. Even >a kludge? I just hacked the following short C-Program which may solve your problem. All you need to know to use it is in the comment at the beginning. --- cut here ---- cut here ---- cut here ---- cut here ---- cut here -- /* * tmdrd -- timed read * * Can be called in shell scripts to read some variable x as follows: * * x=`tmdrd` # times out after 30 seconds, returns empty string * x=`tmdrd -12` # times out after 12 seconds, returns empty string * x=`tmdrd -60 y` # times out after 60 seconds, returns "y" * * BUGS: This program is a quick hack. There could certainly be many * improvements, e.g. checking whether the reason for the bad read was * really a timeout, better handling of defaults, flushing of the input * waiting before the read and after a time out has hit ... * * AUTHOR: Martin Weitzel (martin@mwtech.UUCP) * * Permission to distribute, use, and modify this program is granted to * everyone, with one MAJOR EXCEPTION: The program may NOT be used by any * company that tries to enforce software patents on their work or copy- * rights on their user interfaces. (Sorry, I'm not willing to cooperate * with those who are not willing to cooperate with the rest of the world.) */ static char USAGE[] = "tmdrd [-seconds] [default]"; #include <stdio.h> #include <signal.h> #define TM_DEFAULT 30 /* default time out period */ #define MAX_ANSWER 1000 /* maximum acceptable answer */ static void catcher(sig) int sig; { /*empty*/ } main(argc, argv) int argc; char **argv; { int secs = TM_DEFAULT; char buffer[MAX_ANSWER]; char *answer = ""; int nread; /* check usage */ if (argc > 3) { fprintf(stderr, "Usage %s\n", USAGE); exit(1); } /* extract arguments */ if (argc > 1 && argv[1][0] == '-') secs = atoi(argv[1] + 1); if (argc > 1 && argv[argc-1][0] != '-') answer = argv[argc-1]; /* wait for input */ signal(SIGALRM, catcher); alarm(secs); nread = read(0, buffer, MAX_ANSWER); alarm(0); /* check for timeout condition */ if (nread > 0) { buffer[nread-1] = '\0'; /* delete newline */ answer = buffer; } /* write answer to stdout */ printf("%s", answer); exit(0); } -- Martin Weitzel, email: martin@mwtech.UUCP, voice: 49-(0)6151-6 56 83
daniel@island.COM (Daniel Smith - part of the caffeine generation) (05/30/91)
In <1153@mwtech.UUCP> martin@mwtech.UUCP (Martin Weitzel) writes: > In article <1991May26.165314.21533@midway.uchicago.edu> goer@ellis.uchicago.edu (Richard L. Goerwitz) writes: > >Is there any elegant way to achive a timeout on a read within > >a shell script? Perhaps even "fairly elegant" would do. Even > >a kludge? One way is to get the grabchars package, which allows for timeouts and default answers (and more). A line such as: score=`grabchars -d0 -b -n5 -t10 -r -q 'enter your score >> '` Will set $score to 0 if return is pressed as the first character, or if 10 seconds go by. -b means output to stdout and stderr (so that you can see what you are typing, -t is # of seconds to time out, -n is # of (up to) chars to get, -r means "allow return key". You can get if from comp.sources.misc archives on uunet and elsewhere, or directly from me. Daniel -- daniel@island.com Daniel Smith, Island Graphics, (415) 491 0765 x 250(w) daniel@world.std.com 4000 CivicCenterDrive SanRafael MarinCounty CA 94903 dansmith@well.sf.ca.us Fax: 491 0402 Disclaimer: Hey, I wrote it, not IG! falling/yes I'm falling/and she keeps calling/me back again - IJSaF, Beatles