【问题标题】:bash - `read` cannot read from a redirect, `cat` works fine?bash - `read` 无法从重定向中读取,`cat` 工作正常吗?
【发布时间】:2012-08-17 03:45:13
【问题描述】:

我一直在尝试向我的调制解调器发送一些 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&lt;&amp;-exec 3&gt;&amp;- 似乎不起作用。我必须按 Ctrl+C 才能 重新控制终端。

【问题讨论】:

  • 公认的做法是使用与原始问题相关的信息更新问题。如果这是一个完整的不同问题,那应该是一个新问题。退出更新。

标签: bash exec at-command


【解决方案1】:

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 &lt;&amp;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>&-

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

【讨论】:

    【解决方案2】:

    read 将要读取的描述符作为-u 后面的参数。详情请见help read

    【讨论】:

    • read -r -u3 RESPONSE 给出相同的结果(响应为 AT+CGSN)。
    • 只有一个。对不起,你这是什么意思?
    【解决方案3】:

    如果您想将各个行放入变量中,我建议将 read 包装成 while

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

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

    RESPONSE="$(cat <&3)"
    

    【讨论】:

    • 我仍然建议在读取时设置一个超时,以防调制解调器决定不向您发送OK 行。此外,由于我的回答中指出的原因,最后一个(cat)可能仅仅因为调制解调器没有关闭文件句柄而无法工作。换句话说,它似乎会挂起,因为它会永远等待调制解调器完成。我相信read 解决方案是正确的。
    • @bitmask:使用上面的代码,响应似乎仍然一团糟。它显示每次运行后的不同结果。
    猜你喜欢
    • 2014-05-26
    • 2017-09-23
    • 2015-08-09
    • 2014-07-01
    • 2015-12-21
    • 2017-03-04
    • 1970-01-01
    相关资源
    最近更新 更多