WelcomeWelcome | FAQFAQ | DownloadsDownloads | WikiWiki

Author Topic: Replacement for busybox read -t #  (Read 4923 times)

Offline CentralWare

  • Retired Admins
  • Hero Member
  • *****
  • Posts: 765
Replacement for busybox read -t #
« on: February 11, 2015, 03:48:43 PM »
I have a loop which takes a VERY long time to complete if I have to use 1+ seconds with "read."
There are things within the loop that have to be allowed to finish (umounts, etc.) in order to keep things clean.
I need the ability to abort the loop cleanly by key press, just with a smaller delay than one second.

Code: [Select]
for task in $tasks  # a very long list of tasks
do
     ...do things which don't take long to finish...
     read -n 1 -t 1 keypress     # <-- need 0.xx instead of 1.00 for -t
     if [ ! "x$keypress" == "x" ]; then
          # Break out of this loop
          break
     fi
done
What else could I use to replace the read ( -t 1 ) since it requires whole numbers?
Note: trapping CTRL+C would be an option, just not a PREFERRED one.

Thanks!

Online Rich

  • Administrator
  • Hero Member
  • *****
  • Posts: 11634
Re: Replacement for busybox read -t #
« Reply #1 on: February 11, 2015, 08:45:58 PM »
Hi centralware
How about if you redirect  stdin  to a file. Then periodically test for an empty file. When it's no longer empty, a key was hit.

Online Rich

  • Administrator
  • Hero Member
  • *****
  • Posts: 11634
Re: Replacement for busybox read -t #
« Reply #2 on: February 11, 2015, 09:37:12 PM »
Hi centralware
This appears to work quite well:
Code: [Select]
#!/bin/bash

if [ -t 0 ]; then stty -echo -icanon -icrnl time 0 min 0; fi

count=0
keypress=''
while [ "x$keypress" = "x" ]; do
  let count+=1
  echo -ne $count'\r'
  keypress="`cat -v`"
done

if [ -t 0 ]; then stty sane; fi

echo "You pressed '$keypress' after $count loop iterations"
echo "Thanks for using this script."
exit 0
Found it here:
http://stackoverflow.com/questions/5297638/bash-how-to-end-infinite-loop-with-any-key-pressed

Offline CentralWare

  • Retired Admins
  • Hero Member
  • *****
  • Posts: 765
Re: Replacement for busybox read -t #
« Reply #3 on: February 11, 2015, 09:42:46 PM »
@Rich: Thanks for the tip!  I'm not sure how well this will work with bouncing in and out of sudo (when the key is pressed it could be either state) but I suppose reading the file with sudo wouldn't be that big of a deal.

ie: sudo something...  takes about 4 seconds to complete the loop...  key is pressed.
1>/tmp/keypress would (in theory) be created by root, thus "tc" would be given perms problems.

I'm looping through the entire 4.x repository (local copy) getting a binary vs. text database going which will eventually be sent through dependency checking to see if I can create a .tree file with more specific data (ie: needing menu.c32...  instead of the entire syslinux package) so this is just a test run to see what caveats are to be expected.  The end result is going to basically help me with remastering an image with "just the needed pieces" but I kept finding too many packages (and dependencies of those packages) where only one or two files are needed as opposed to a hundred.  With all of the extensions in 4.x, many of which don't have .tree and/or .dep files, it's been "fun" for a lack of better words! :)

Offline CentralWare

  • Retired Admins
  • Hero Member
  • *****
  • Posts: 765
Re: Replacement for busybox read -t #
« Reply #4 on: February 11, 2015, 09:51:41 PM »
@Rich: Thanks for the second tip, but it's not BusyBox friendly ("cat" does not have -v as an option.)  That was the first direction I ventured.  :P

Online Rich

  • Administrator
  • Hero Member
  • *****
  • Posts: 11634
Re: Replacement for busybox read -t #
« Reply #5 on: February 11, 2015, 10:06:31 PM »
Hi centralware
Then use it without -v. Also, have you tried setting the timeout in  read  to zero?

Offline CentralWare

  • Retired Admins
  • Hero Member
  • *****
  • Posts: 765
Re: Replacement for busybox read -t #
« Reply #6 on: February 11, 2015, 10:24:32 PM »
@Rich: Please forgive me if I'm wrong...  I was always under the assumption that --timeout=0 meant "wait forever" such as waiting for a user to enter input and just sit there glaring with a blinking cursor, so to speak, until interacted?

ie: read -n 1 --timeout=0 keypress I thought just waited until something was done keyboard wise.

Online Rich

  • Administrator
  • Hero Member
  • *****
  • Posts: 11634
Re: Replacement for busybox read -t #
« Reply #7 on: February 11, 2015, 10:36:56 PM »
Hi centralware
I just reread the man page and I think you may be right. Try the posted code, it's quite fast. Even with the echo command the loop
executes 150 times per second even on my slow PC.

Offline CentralWare

  • Retired Admins
  • Hero Member
  • *****
  • Posts: 765
Re: Replacement for busybox read -t #
« Reply #8 on: February 11, 2015, 10:41:49 PM »
LOL...  might have to port old GBasic to get the "A$=inkey" functionality :)  (Think I got that right...  it's only been about two decades!)

Online Rich

  • Administrator
  • Hero Member
  • *****
  • Posts: 11634
Re: Replacement for busybox read -t #
« Reply #9 on: February 11, 2015, 10:50:23 PM »
Hi centralware
I know it as  keyhit  in C though that's specific to Microsoft. The first  stty  command puts the terminal in non-blocking mode so the script
functions just like inkey and returns the result immediately. The second  stty  command restores the terminal to "sane" settings.


Offline CentralWare

  • Retired Admins
  • Hero Member
  • *****
  • Posts: 765
Re: Replacement for busybox read -t #
« Reply #10 on: February 12, 2015, 12:03:37 AM »
Hi Rich!

I've all but scrapped most of my programming (with TC) and focused most of my efforts into ASH (since there's so many differences from bash I try to implement as much as I can "raw" instead of adding bash to the mix - and to be honest, I've always used bash...  so it's been a mean learning curve! :) )  Plus, I like the idea of not relying on libraries and not having to re-invent the wheel...  so if I have to start a fire with a pair of sticks, it's worth it!

I couldn't get the timeout=0 to "catch" a key stroke seemingly fast enough (or maybe the task was busy) thus it looked as though there was no keyboard buffer for when the script was busy and it "got lost" somewhere.

I broke down and trapped int/kill/etc. as a temporary measure, but I'd like to eventually come across a solid "catch me" key stroke reader which is BZBox friendly as I'd imagine it'll come in handy for building menus and the likes without user input requiring an ENTER being hit.  My sincerest thanks for your assistance!  I'll dig into this more tomorrow when I've had a chance to recharge my own power cells!

Good night and take care!

Online Rich

  • Administrator
  • Hero Member
  • *****
  • Posts: 11634
Re: Replacement for busybox read -t #
« Reply #11 on: February 12, 2015, 12:23:20 AM »
HI centralware
I didn't notice the reference to bash in the she-bang. I tried it with both  ash  and  sh and explicitly called  busybox cat  with no problems.
Does it not work for you?

Offline CentralWare

  • Retired Admins
  • Hero Member
  • *****
  • Posts: 765
Re: Replacement for busybox read -t #
« Reply #12 on: February 12, 2015, 10:39:13 AM »
Good day Rich!

No, the first attempt was unsuccessful (which I had done prior to posting).  I think I might know why, though.
Here's a basic skeleton of what's being done.  (The actual script is about 3 pages long, otherwise I'd post the original)

Code: [Select]
#!/bin/sh

## Some prep code to clean up from the last time the program was run
...
## A bunch of utility functions relating to parsing text, downloading files, etc.
...
my_function()
{
     # This function takes anywhere between 1 and 10 seconds to complete
     # depending on the size of the extension being worked on and the number
     # of dependencies it has.  This function "has" to complete, otherwise it will
     # likely leave files mounted/locked, partially written, etc. (gets messy)

     sleep 5
}

if [ -t 0 ]; then stty -echo -icrnl -icanon time 0 min 0; fi

exts=`cat /path/to/extension/list/filename.txt`
for ext in $exts
do
     # Check keypress through cat
     keypress="`cat`"; if [ ! "x$keypress" == "x"; then break; fi

     # Call above function to process the next extension
     my_function $ext
done

if [ -t 0 ]; then stty sane; fi

echo; echo "Script Ended Cleanly"

NOTE: I just went back to the first test script and it failed...  until I held down the space-bar, which then was detected.  As assumed, there's no keyboard "buffer" thus when detecting keys using redirection, the detection (ie: with "cat" in this case) has to be done at the exact instance the key is pressed or the loop testing for a keypress must be 'x' number of times per second so it doesn't "miss" the pressed key.

For example, let's say I was extracting a couple dozen files.  I have to call outside the script (ie: tar -zxf) where during the time the file is decompressing, you can "key-press" all you'd like and it won't be seen when control gets back to the calling script.

[scratches one's head and murmurs "...hmmmm..."]

Online Rich

  • Administrator
  • Hero Member
  • *****
  • Posts: 11634
Re: Replacement for busybox read -t #
« Reply #13 on: February 12, 2015, 11:28:14 AM »
Hi centralware
I just tried this and it works:
Code: [Select]
#!/bin/sh

timeout()
{
echo sleeping
sleep 2
echo awake
}

if [ -t 0 ]; then stty -echo -icanon -icrnl time 0 min 0; fi

keypress=''
while true
do
  keypress="`cat`"; if [ ! "x$keypress" == "x" ]; then break; fi
  timeout
done

if [ -t 0 ]; then stty sane; fi

echo "Thanks for using this script."
exit 0
I press a key when it's sleeping and when it wakes up the loop terminates.

I noticed you seem to be missing a  ]  here:
Code: [Select]
     # Check keypress through cat
     keypress="`cat`"; if [ ! "x$keypress" == "x"; then break; fi

Offline CentralWare

  • Retired Admins
  • Hero Member
  • *****
  • Posts: 765
Re: Replacement for busybox read -t #
« Reply #14 on: February 12, 2015, 11:46:33 AM »
@Rich: Sorry for the missing bracket...  I was typing it in (not pasting)
I was able to manage a working copy, but it's going to require peppering "my_function" with checks...
Code: [Select]
#!/bin/sh
cur=`pwd`

capturing=0
exiting=0

start_capture()
{
    trap exit_trap SIGINT
    trap exit_trap SIGKILL
    trap exit_trap SIGTERM

    if [ -t 0 ]; then
stty -echo -icanon -icrnl time 0 min 0
    else
echo "Unable to capture key-press"
    fi

    capturing=1
}

exit_trap()
{
    exiting=1
    echo; echo "Trap Received - Aborting"
}

stop_capture()
{
    capturing=0
    if [ -t 0 ]; then stty sane; fi
}

keycheck()
{
    if [ $capturing -gt 0 ]; then
keypress="`cat`"
if [ ! "x$keypress" == "x" ]; then
    echo; echo "Aborting"
    exiting=1
fi
    fi
}

my_function()
{
    echo -n "Doing Something"
    count=5
    while [ $count -gt 0 ]
    do
         echo -n "."
         sleep 1
         counting=$((counting-1))
         # Add check here to see if $exiting -gt 0 otherwise it could be 10 seconds before notification?!
    done
    echo
}

start_capture

exts=`cat $cur/apps.lst`
for ext in $exts
do
    my_function
    keycheck
    if [ $exiting -gt 0 ]; then break; fi
done

stop_capture

echo "End Of Script"; exit 0;
Note: apps.lst is a complete file listing of TC's tcz directory (in this case 4.x/x86/tcz)