bash - `read`无法从重定向读取,`cat`工作正常?

时间:2012-08-17 03:45:14

标签: bash exec at-command

我一直在尝试向我的调制解调器发送一些AT命令,并希望将响应捕获到变量中。这是我的代码:

exec 3<>/dev/ttyUSB3

echo -e "AT+CGSN\n" >&3

cat <&3
#read -r RESPONSE <&3
#echo "Response was $RESPONSE"

exec 3<&-
exec 3>&-

结果:

$ ./imei_checker.sh 
AT+CGSN


356538041935676



OK

AT+CGSN


356538041935676



OK

但如果我将cat更改为read,则无法正常工作:

$ ./imei_checker.sh 
Response was AT+CGSN

另外2个问题:

  1. 为什么它显示了重复的输出?
  2. 如何正确关闭文件句柄? exec 3<&-exec 3>&- 似乎不起作用。我必须按 Ctrl + C 来 控制终端回来了。

3 个答案:

答案 0 :(得分:2)

read只读取一行,与cat不同,它基本上会读取并回显直到文件结尾。

对于read版本,您最好在超时时读取,直至获得OK(并存储包含大量数字的任何行)。

我认为你会发现这不是关闭3号文件句柄的东西 - 它更可能是cat 继续读取/回显直到没有发生的文件结束事件。

如果您只是提出:

,您可以确定
echo XYZZY
在结束exec陈述之前

。如果它仍然在cat,你将永远不会看到它。

因此,使用循环read版本也可能会解决这个问题。


举例来说,以下是使用read标准输入执行此操作的方法:

#!/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'"

它使用read的超时功能来检测是否没有更多输入(将输入设置为OK以强制循环退出)。如果之前得到OK,它无论如何都会正常退出,超时只是为了满足调制解调器未按预期应答的可能性。

这个数字最初设置为“从调制解调器”中以数字开头的任何行覆盖。

两次示例运行,包含和不包含“调制解调器”的OK响应:

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: ''

将它转换为与您的调制解调器设备类似的东西并不太难(read <&3read -u3可以正常工作)。


这基本上会转换为您的环境:

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>&-

现在我没有测试,因为我没有连接调制解调器(现在已经在宽带上使用了很长一段时间)但它应该关闭到你需要什么,如果不是确切的话。

答案 1 :(得分:1)

read将描述符作为-u后面的参数读取。有关详细信息,请参阅help read

答案 2 :(得分:1)

如果您想将各行变为变量,我建议将read包裹到while中:

while read -r RESPONSE <&3; do
  echo "Response was $RESPONSE"
  ## e.g.:
  [ "$RESPONSE" = "OK" ] && break
done

但是,如果您希望发回给您的“所有内容”都驻留在$RESPONSE中,您可以这样做:

RESPONSE="$(cat <&3)"