GermainZ
GermainZ

Reputation: 1943

Command giving no output when being read

I have a rather weird issue. I can't figure out why it's happening or how to fix it.

The script:

#!system/bin/sh
#set -x

reader() {
    t2=-1
    grep -v -E "add device|name:" | while IFS=' ' read -r t1 a b c d _; do
        t1=${t1%%-*}
        t=`expr $t1 - $t2`
        if let 't > 0 && t2 > -1'; then
            echo "sleep $t"
        fi
        printf 'sendevent %s' "${a%?}"
        printf '%5d %5d %5d\n' "0x$b" "0x$c" "0x$d"
        t2=$t1
    done
}

let() {
    IFS=, command eval [ '$(($*))' -ne 0 ]
}

countDown() {
    echo 'Starting in...'
    i=4
    while [[ $i -gt 1 ]]; do
        i=$(($i-1))
        echo "$i"
        sleep 1
    done
    printf '%s\n\n\n' 'Go!'
#    echo "$*"
    "$@" | reader
}

clear
printf '%s >' 'Catch by [n]umber of events or [t]imeout?'
read type

case $type in
    n)
        printf '%s >' 'Events to catch?'
        read arg
        echo "Gonna catch $arg events!"
        countDown getevent -t -c "$arg"
        ;;
    t)
        printf '%s >' 'Timeout (in seconds)?'
        read arg
        echo "Gonna catch events for $arg seconds!"
        countDown timeout -t $arg getevent -t
esac

The goal of the script:

Catch the user's interactions (e.g., key presses, screen taps, etc.) using the getevent command and outputs a script to standard output, that can be used to replicate these events.

Additional information:

getevent's output is in hexadecimal format, and sendevent accepts decimal format.

Expected output:

Catch by [n]umber or by [t]imeout? n
Events to catch? > 4
Gonna catch 4 events...
Starting in...
3
2
1
Go!
sendevent /dev/input/event5 1 102 1
sendevent /dev/input/event5 0 0 0
sleep 3
sendevent /dev/input/event5 1 102 0
sendevent /dev/input/event5 0 0 0

The problem:

The code runs as expected when "n" is picked. When "t" is picked, the script exits after the specified amount of seconds. However, it does not output anything - the first line of the while loop doesn't even run.

With set -x, here's what's shown (last few lines):

+ printf %s\n\n\n Go!
Go!
+ reader
+ t2=-1
+ grep -v -E add device|name:
+ timeout -t 5 getevent -t
+ IFS =  read -r t1 a b c d _

Running this alone shows output to standard output (output that's supposed to be read and modified inside the while loop):

timeout -t 5 getevent -t

Any ideas?

All right, so I think it's a buffering issue. Basically this gives a similar issue:

 `getevent > output`

The file gets updated every bunch of events, but not instantly (and might never update if not enough events are made). I'm not aware of any work around on Android.

Upvotes: 2

Views: 1559

Answers (3)

ormaaj
ormaaj

Reputation: 6577

Here was basically that stuff I translated from your code before being mangled by bug workarounds. Replacing the one command I don't have with cat on the timeout branch, it runs correctly with your sample input in BusyBox sh, Dash, mksh, Bash, and KornShell 93.

Since so many basic things about the shell and applications are broken, it isn't surprising this doesn't work. I would make sure BusyBox is up-to-date and see whether the arithmetic and other bugs you keep hitting are reproducible on other systems, and report bugs if this code doesn't work.

#!/bin/sh

reader() {
    t2=-1
    grep -vE '^(add device|[[:space:]]+name:)' |
    while IFS=' ' read -r t1 a b c d _; do
        let "(t = (t1 = ${t1%%-*}) - t2) > 0 && t2 > -1" && echo "sleep $t"
        printf 'sendevent %s' "${a%[[:digit:]]:}"
        printf '%5d %5d %5d\n' "0x$b" "0x$c" "0x$d"
        let t2=t1
    done
}

let() {
    IFS=, command eval test '$(($*))' -ne 0
}

countDown() {
    echo 'Starting in...'
    i=4
    while let 'i-=1 > 0'; do
        echo "$i"
        sleep 1
    done
    printf '%s\n\n\n' 'Go!'
    echo "$*"
    "$@" <&3 | reader
}

isDigit() {
    while ! ${1+false}; do
        case $1 in
            *[^[:digit:]]*|'') return 1
        esac
        command shift
    done 2>/dev/null
}

main() {
    printf '%s >' 'Catch by [n]umber of events or [t]imeout?'
    read type

    case $type in
        n)
            printf '%s >' 'Events to catch?'
            read arg
            isDigit "$arg" || return 1
            echo "Gonna catch $arg events!"
            countDown getevent -t -c "$arg"
            ;;
        t)
            printf '%s >' 'Timeout (in seconds)?'
            read arg
            isDigit "$arg" || return 1
            echo "Gonna catch events for $arg seconds!"
            countDown busybox timeout -t "$arg" cat -
            ;;
        *)
            return 1
    esac
}

main "$@" 4<&0 <<\EOF 3<&0 <&4 4<&-
add device 1: /dev/input/event8
  name:     "bcm_headset"
add device 2: /dev/input/event7
  name:     "max8986_ponkey"
add device 3: /dev/input/event6
  name:     "sec_touchscreen"
add device 4: /dev/input/event5
  name:     "sec_keypad"
add device 5: /dev/input/event4
  name:     "orientation"
add device 6: /dev/input/event3
  name:     "accelerometer"
add device 7: /dev/input/event0
  name:     "proximity_sensor"
add device 8: /dev/input/event2
  name:     "geomagnetic_raw"
add device 9: /dev/input/event1
  name:     "geomagnetic"
45534-48646 /dev/input/event6: 0001 008b 00000001
45534-48646 /dev/input/event6: 0000 0000 00000000
45534-48646 /dev/input/event6: 0001 008b 00000000
45534-48646 /dev/input/event6: 0000 0000 00000000
EOF

# vim: set fenc=utf-8 ff=unix ft=sh :

Command:

bb --help

Output:

BusyBox v1.21.0 (2013-02-20 20:39:21 CST) multi-call binary.

Usage: bb [-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]

Unix shell interpreter

And:

bb answers/countdown

Output:

Catch by [n]umber of events or [t]imeout? >t
Timeout (in seconds)? >5
Gonna catch events for 5 seconds!
Starting in...
3
2
1
Go!

And:

busybox timeout -t 5 cat -

Output:

sendevent /dev/input/event6:    1   139     1
sendevent /dev/input/event6:    0     0     0
sendevent /dev/input/event6:    1   139     0
sendevent /dev/input/event6:    0     0     0

Upvotes: 2

Diego Torres Milano
Diego Torres Milano

Reputation: 69189

I think there isn't any way of enabling line-buffering in BusyBox's grep, but you can do something like this:

adb shell timeout -t 10 getevent -t | \
    grep --line-buffered -v -E "add device|name:" | \
    while read line; do echo "READ: $line"; done

Upvotes: 2

Zwaa KwaZuluNatal
Zwaa KwaZuluNatal

Reputation: 1

I had the same problem, and remembered a trick that I first used in MS-DOS 3.30, and later in Cygwin (not for timeout, but the more command is a magical bullet for lots of redirect problems):

timeout -t 8 getevent | more > getevent.txt

It works well in Total Commander's shell with su (not sh).

Upvotes: 0

Related Questions