Reputation: 4530
I've been trying to send some AT commands to my modem and want to capture response into a variable. Here's my code:
exec 3<>/dev/ttyUSB3
echo -e "AT+CGSN\n" >&3
cat <&3
#read -r RESPONSE <&3
#echo "Response was $RESPONSE"
exec 3<&-
exec 3>&-
Results:
$ ./imei_checker.sh
AT+CGSN
356538041935676
OK
AT+CGSN
356538041935676
OK
But if I change cat
to read
, it doesn't work:
$ ./imei_checker.sh
Response was AT+CGSN
2 more questions:
exec 3<&-
and exec 3>&-
seems doesn't work. I have to press Ctrl+C to
get control of the Terminal back.Upvotes: 2
Views: 996
Reputation: 881273
read
will only read a single line, unlike cat
which will basically read and echo until end of file.
For a read
version, you're best off reading with a timeout up until the point you get the OK
(and storing any line that contains a lot of digits).
I think you'll find that it's not the closing of the number 3 file handle that's stopping things - it's more likely to be the cat
which will continue to read/echo until an end-of-file event that isn't happening.
You can be certain of this if you just put:
echo XYZZY
immediately before the closing exec
statements. If it's still in the cat
, you'll never see it.
So, using a looping read
version will probably fix that as well.
By way of example, here's how you can use read
to do this with standard input:
#!/bin/bash
NUM=
while true ; do
read -p "> " -t 10 -r RESP <&0
if [[ $? -ge 128 ]] ; then RESP=OK ; fi
echo "Entered: $RESP"
if [[ $RESP = OK ]] ; then break ; fi
if [[ $RESP =~ ^[0-9] ]] ; then NUM=$RESP ; fi
done
echo "Finished, numerics were: '$NUM'"
It uses the timeout feature of read
to detect if there's no more input (setting the input to OK
so as to force loop exit). If you do get an OK
before then, it exits normally anyway, the timeout simply caters for the possibility that the modem doesn't answer as expected.
The number is set initially to nothing but overwritten by any line from the "modem" that starts with a number.
Two sample runs, with and without an OK
response from the "modem":
pax> ./testprog.sh
> hello
Entered: hello
> 12345
Entered: 12345
> OK
Entered: OK
Finished, numerics were: '12345'
pax> ./testprog.sh
> hello
Entered: hello
> now we wait 10 secs
Entered: now we wait 10 secs
> Entered: OK
Finished, numerics were: ''
It wouldn't be too hard to convert that to something similar with you modem device (either read <&3
or read -u3
will work just fine).
That would basically translate to your environment as:
exec 3<>/dev/ttyUSB3
echo -e "AT+CGSN\n" >&3
NUM=
while true ; do
read -t 10 -r RESP <&3
if [[ $? -ge 128 ]] ; then RESP=OK ; fi
echo "Entered: $RESP"
if [[ $RESP = OK ]] ; then break ; fi
if [[ $RESP =~ ^[0-9] ]] ; then NUM=$RESP ; fi
done
echo "Finished, numerics were: '$NUM'"
exec 3<&-
exec 3>&-
Now I haven't tested that since I don't have a modem hooked up (been on broadband for quite a while now) but it should be close to what you need, if not exact.
Upvotes: 2
Reputation: 34628
If you want to get the individual lines into variables I'd suggest to wrap read
into a while
:
while read -r RESPONSE <&3; do
echo "Response was $RESPONSE"
## e.g.:
[ "$RESPONSE" = "OK" ] && break
done
However, if you want "everything" that is sent back to you to reside in $RESPONSE
you could do it like this:
RESPONSE="$(cat <&3)"
Upvotes: 1
Reputation: 798546
read
takes the descriptor to read from as the argument following -u
. See help read
for details.
Upvotes: 1