Read input data within a specified period of time

Hi All,

I am working on a script which requires an input from user within one 1 min.

So if the user gives the required input within 1 min., it will execute on the basis of input provided by the user.Other wise it will execute on a default value(hard coded inside the script).

Now, I am able to hard code the default input, but I get stuck when I need to pass the input within 1 min.

I am not sure how to specify the time period within which it gets input from the user.If doesnot get the user input within 1 min, it executes on the default values.

May be I have to use sleep command in loop to get this done, but I am not sure at this moment.!!

Any body having any idea, how this can be done?
BTW, I am using AIX 5.3, working on k-shell.
Appreciate ur efforts.
Regards,
raj.

The read command in KSH has a switch to define a timeout (-t). Example usage:

echo "Input (timeout 10 seconds):"
read -t 10 userinput
if [ $? -ne 0 ]
then
    echo "Using default value"
else
    echo "Using user input"
fi
1 Like

Thank Pludi for quick answer.

But looks like AIX 5.3 doesnot seem to have this switch.Is there any other way.

Appreiciate ur help.
Regards,
Raj.

use #!/bin/ksh93 instead of #!/bin/ksh

1 Like

I have named the script as delay.sh and It gives the following error.

Error:
bsd:dir1/users/usename/Files>sh delay.sh
Input (timeout 10 seconds):
delay.sh[3]: read: 0403-010 A specified flag is not valid for this command.
Using default value

How can I fix the error?
Regards,
raj.

It works when I run the script as ksh93 delay.sh.
I waits for 10 seconds... and in the mean time user gives input....It proceeds on the basis of that else i takes default value.

Thanks a lot for ur help.Appreciate ur effort and time.
Cheers
raj.

---------- Post updated at 02:46 AM ---------- Previous update was at 02:23 AM ----------

#############################################
I tested ur code. Its nice. How ever after entering the user input I have to hit
"ENTER" button. Is there way can remove the need of entering "Enter Key"?

Thanks a lot.
raj

If you don't hit enter, how is read supposed to know that all input has been read?

If u want to catch only some number of characters (i.e. only 2 or only 5 characters need to be entered and than your standard input should be disabled) than I have perl code if u have perl installed in your machine.

HI ROHON, I do have perl installed in my system.
But the requirement is such that I dont have to hit "Enter key" and I have to give "date" as user input in the format like 2010-12-15, so it has length of 10.

I think short perl code wud be fine as I am not much familiar with PERL.

Appreciate ur time,
Regards,
Raj.

My perl code exactly match your requirement. It will not accept "Enter Key" as an input. Actually it will, but doesn't react on it. So, if u want to accept only 10 characters than it will be helpful. Also I have seen your previous posts, in which u were demanding a time limit. So, I have modified my perl program and storing input value in one file. After 10 seconds, I will check if file is empty than assign default value else assign entered value.

Your shell script

echo "Enter input:\c"
charReading.pl 10 &
pid=$!
sleep 10
if [ ! -f "/tmp/optFile" ] ; then
    echo "Using input value"
else
    kill -9 $pid
    echo "Using default value"    
fi

My perl code

 #! /usr/bin/perl -w
#
# Usage:
#     charReading.pl <Number of Chars to read>
#     charReading.pl 10        # In your case
#

my $maxChars = $ARGV[0];

use strict;
use FileHandle;
my $FOBJ = new FileHandle ">/tmp/optFile";

$| = 1;
my $finalString = "";

while ($maxChars != 0) {
    my $khatm = 0;
    for (1..$maxChars) {
        my $cChar;
        $cChar = getOneChar();
        if ($cChar ne "\n") {
        if ($cChar eq "\b") {
            chop($finalString);
            print "$cChar \b";
            $khatm += 2;
        } else {
            $finalString .= $cChar;
            print "$cChar";
        }
        } else {
            $khatm += 1;
        }
    }
    $maxChars = $khatm;
}

print $FOBJ "$finalString";
exit; 

BEGIN {
    use POSIX qw(:termios_h);  
    my ($term, $oterm, $echo, $noecho, $fd_stdin);
    $fd_stdin = fileno(STDIN);
    $term = POSIX::Termios->new();
    $term->getattr($fd_stdin); 
    $oterm = $term->getlflag();
    $echo = ECHO | ECHOK | ICANON;
    $noecho = $oterm & ~$echo; 

    sub cbreak {
        $term->setlflag($noecho);
        $term->setcc(VTIME, 1);
        $term->setattr($fd_stdin, TCSANOW); 
    }  
   
    sub cooked {
        $term->setlflag($oterm);
        $term->setcc(VTIME, 0);
        $term->setattr($fd_stdin, TCSANOW);  
    }    
    sub getOneChar { 
        my $key = '';
        cbreak();  
        sysread(STDIN, $key, 1); 
        cooked(); 
        return $key;  
    }  
}
END {
    cooked()
}

After this u need to validate the input as it should be in the date formate.

you can try this :wink:

 ## justdoit ##
#!/bin/ksh
trap "" 2
readit() {
case $2 in
year ) message="year[YYyy]" ;;
month ) message="month[mm]" ;;
day ) message="day[dd]" ;;
esac
printf "... %s $message ...= "  && read -n $1 $2
while [ "$(echo $(eval echo "\$$2"|sed 's/[0-9][0-9]*//g' ))" != "" ]
 do
   printf "\n%s pls input only digits!!\n" ;
   printf "... %s $message ...= " && read -n $1 $2
 done
echo ;
}
readit 4 year ; readit 2 month ; readit 2 day
if [ $? -eq 0 ] ; then echo "$year-$month-$day" ; fi

Hi ROHON, thanks for the code.

Here is how I tried ur code.
I named the script as dlay.sh

#!/usr/bin/sh
echo "Enter input:\c"
/usrdir/charReading.pl 10 &
pid=$!
sleep 10
if [ ! -f "/tmp/optFile" ] ; then
    echo "Using input value"
else
    kill -9 $pid
    echo "Using default value"    
fi

and I saved perl code charReading.pl in the dir:/usrdir/

Then I run the script dlay.sh
I hope this is how You run ur script as well.

But , I get an error :

Enter input:2010-12-12kill: 5517524: 0403-003 The specified process does not exist.
Using default value

That was one way.....

##############
2nd way:
If I treat the perl code as a function, so the script and perl code are in the same program say testdelay.sh then it gives following error:

Enter input:2010-12-12
kill: 6877242: 0403-003 The specified process does not exist.
Using default value
testdelay.sh[18]: my:  not found.
testdelay.sh[20]: use:  not found.
testdelay.sh[21]: use:  not found.
testdelay.sh[22]: my:  not found.
testdelay.sh[24]: $:  not found.
testdelay.sh[24]: =:  not found.
testdelay.sh[25]: my:  not found.
testdelay.sh[27]: 0403-057 Syntax error at line 28 : `{' is not expected.

Hope its clear... and thanks again for your time.

Regards,
Raj.

Do u understand what u have written? First confirm me that charReading.pl program is running perfectly. I mean execute it as below and make sure it accepts only 5 characters. After than control comes back to the prompt. Also confirm that /tmp/optFile contains exactly what u have entered.

$ charReading.pl 5
rohon
$ cat /tmp/optFile
rohon

bsduser: perl charReading.pl 5
rohon
bsduser: cat /tmp/optFile
rohonbsduser:

That is /tmp/optFile contains "rohonbsduser:" instead of "rohon".
I am not sure...but I think ... once I do "cat /tmp/optFile" and then hit "enter", this
"bsduser:" just gets appeneded to "rohon" which is what we are expecting.

Regards,
raj.

Ok. Thats fine. charReading.pl is running fine. Now run follwing code. There was a small error in logic. Now it is correct.

#!/usr/bin/ksh
echo "Enter input:\c"
/usrdir/charReading.pl 10 &
pid=$!
sleep 10
if [ -s "/tmp/optFile" ] ; then
    echo "Using input value"
else
    kill -9 $pid
    echo "Using default value"    
fi

Thanks for reply. Here is how I run it.
The name of script is delay.sh

sh delay.sh
Enter input:2010-12-12
kill: 3956770: 0403-003 The specified process does not exist.
Using default value

Thanks for ur efforts ROHON,appreciate it.. but it is not able to locate that process.
What do you think..?

Regards,
raj

Will u run it as following and revert with the entire output comes on your screen. It is for debugging a script.

$ ksh -x delay.sh

ROHON, Here is debugging result:

ksh -x delay.sh
+ echo Enter input:\c
Enter input:+ perl /usrdir/charReading.pl 10
+ pid=6570172
+ sleep 10
2010-12-12+ [ -s /tmp/optFile ]
+ kill -9 6570172
kill: 6570172: 0403-003 The specified process does not exist.
+ echo Using default value
Using default value

Thanks
raj

Hi Raj Sharma,
Sorry for the late replying. I have made some changes in both the codes. Please try this and revert if not done.

Shell script �delay.sh�

 > timeoutFile                     # Creating one 0 byte file
  echo "Enter input:\c"
  charReading.pl 10 &
  pid=$!
  sleep 10
  if [ -s "timeoutFile" ] ; then     # This means something has been entered in between 10 seconds of sleep which was recorded in this file. So, if this file is not empty after 10 seconds then no timeout.
      input=`cat /tmp/optFile`

    echo "Using input value = [${input}]"
  else
      kill -9 $pid
      echo "Using default value"    
  fi 

Perl code �charReading.pl�

 #! /usr/bin/perl -w
  #
  # Usage:
  #     charReading.pl <Number of Chars to read>
  #     charReading.pl 10        # In your case
  #
   
  my $maxChars = $ARGV[0];
   
  use strict;
  use FileHandle;
  my $FOBJ = new FileHandle ">/tmp/optFile";
   
  $| = 1;
  my $finalString = "";
   
  while ($maxChars != 0) {
      my $khatm = 0;
      for (1..$maxChars) {
          my $cChar;
          $cChar = getOneChar();
          system("echo kaipan > timeoutFile");    # Echoing kaipan in timeoutFile if user has entered any character
          if ($cChar ne "\n") {
          if ($cChar eq "\b") {
              chop($finalString);
              print "$cChar \b";
              $khatm += 2;
          } else {
              $finalString .= $cChar;
              print "$cChar";
          }
          } else {
              $khatm += 1;
          }
      }
      $maxChars = $khatm;
  }
   
  print $FOBJ "$finalString";
  exit; 
   
  BEGIN {
      use POSIX qw(:termios_h);  
      my ($term, $oterm, $echo, $noecho, $fd_stdin);
      $fd_stdin = fileno(STDIN);
      $term = POSIX::Termios->new();
      $term->getattr($fd_stdin); 
      $oterm = $term->getlflag();
      $echo = ECHO | ECHOK | ICANON;
      $noecho = $oterm & ~$echo; 
   
      sub cbreak {
          $term->setlflag($noecho);
          $term->setcc(VTIME, 1);
          $term->setattr($fd_stdin, TCSANOW); 
      }  
     
      sub cooked {
          $term->setlflag($oterm);
          $term->setcc(VTIME, 0);
          $term->setattr($fd_stdin, TCSANOW);  
      }    
      sub getOneChar { 
          my $key = '';
          cbreak();  
          sysread(STDIN, $key, 1); 
                                  cooked(); 
          return $key;  
      }  
  }
  END {
      cooked()
  } 

Hi ROHON,

Sorry for replying too late,was out of station.

When I run ur latest code as:
sh delay.sh
Enter input:2010-12-12
Using input value = []

Seems to work fine when I give some input string and do not press "enter".
But in this case /tmp/optFile doesnot store anything.I do not know the reason!

When I run it withoutgiving any input as
sh delay.sh
Enter input:Using input value = []

It shud give output as "Using Default value".

And more, when I run it in debuging mode as:
sh -x time.sh
+ 1> timeoutFile
+ echo Enter input:\c
Enter input:+ perl /usrdir/charReading.pl 10
+ pid=8568904
+ sleep 10
2010-12-12+ [ -s timeoutFile ]
+ + cat /tmp/optFile
input=
+ echo Using input value = []
Using input value = []

I hope this could give u some indications.
Thanks for ur time,
Regards,
raj.

It is becuase the input is stored in /tmp/optFile at the end of the charReading.pl program execution. So, u will not find anything in that file untill charReading.pl program in running.

Little bit of change in shell script.

if [ -s "timeoutFile" ] ; then
      while ps -p $pid ; do            # This will ensure that charReading.pl process is completed.
         sleep 1
      done         
      input=`cat /tmp/optFile`         # After that only input will be fetched from optFile
      echo "Using input value = [${input}]"
else
      kill -9 $pid
      echo "Using default value"    
fi