我目前正在尝试开发一个脚本,该脚本将连接到 Fluke DewK 1620a 温湿度计并从设备中提取当前的温度和湿度读数。虽然这些设备上有一个网络端口,但该端口上似乎没有通用协议侦听。它们只是接受原始 TCP 连接。我可以通过 netcat 和 putty 进行交互连接、传递命令并接收输出。我尝试通过 netcat 编写脚本(请参阅“通过 netcat 从 Fluke 1620a 捕获数据”),但根本无法使其发挥作用。从那时起,我发现我可以使用 Bash 的独特功能来完成我的任务,即在 TCP 连接上打开文件描述符读/写。虽然我现在能够将数据捕获到文件中,但我正在努力解决我所知道的可能是一些非常基本的问题。
#!/bin/bash
$host=1.2.3.4
$port=10001
$location=lab1
$log=${location}_DewK.log
$datetime=$(date +%F_%T)
exec 3<>/dev/tcp/${host}/${port}
echo -e "read?" >&3 # Sends the read? command to the Fluke.
printf ${datetime} >> ${log} # Inserts a timestamp to the log.
cat <&3 | tee -a ${log} & # Tee was the only way I could get it to log.
sleep 1 && pkill cat # The cat just hangs out there & will not end.
exec 3<&-
exec 3>&-
我知道它很丑陋,但我似乎无法弄清楚如何提高它的效率。我的主要问题是:
- “cat <&3”会导致各种问题。没有 EOF,所以它永远挂在那里。我已经使用 read 尝试了很多不同的方法,但似乎无法让它工作。 “cat”似乎是我可以将数据提取并写入文件的唯一方法,但必须使用“pkill”以防止它占用传感器。
- 我很想将结果读入 $results 之类的变量中,但似乎无法使用“cat”来实现这一点。我怀疑我遗漏了一些非常简单的东西,但似乎无法弄清楚。
Fluke 的输出类似于“76.05,56.3,72.89,59.0^M”。我知道这是因为它没有检测到 EOL,但我不知道如何在“cat <&3”之后添加新行。结果是一个如下所示的日志:
2014-11-26_07:09:03
75.75,56.4,72.53,59.7^M2014-11-26_07:09:05
75.75,56.4,72.54,59.7^M2014-11-26_07:09:07
75.75,56.4,72.53,59.7^M
我的目标是在每次运行时将“${datetime} - ${results}”写入日志文件的一行,但我不知道如何组合这些行。我想答案在于将结果放入我可以使用的变量中。
我很感激我能得到的任何帮助。我一直在翻阅手册页、bash 文档、博客文章,当然还有这个网站。我在这里收集的信息确实是我走到这一步的唯一原因。我只是超出了我的能力范围,正在参加速成课程。
答案1
我不清楚您是否得到每个结果一个结果read?
,或者是否得到一串结果。我认为你说的是一个请求->一个回复。而且您从未提供过十六进制转储或任何输出,但看起来行结尾可能只是 CR,而不是 DOS CR-LF 或 unix LF。 (这就是为什么你的提示会覆盖 netcat 之后的输出。)
我确实找到了手册: http://us.flukecal.com/literature/product-manuals/1620a-user%E2%80%99s-guide
它确认响应以 CR 终止。这使得在 shell 中使用变得非常痛苦,因为它tr '\r' '\n'
有与 cat 相同的问题:它不会在一行之后停止。
# read -d sets the delimiter.
# $'' is a special type of quoting where \r expands to a literal carriage return.
get_temp () { # io to fluke on FD 3
echo "read?" >&3
local resp
IFS= read resp -d $'\r' -u 3
printf '%s\n' "$resp"
}
exec 3<>"/dev/tcp/$host/$port"
while true; do # whole loop is redirected to log
temp="$( get_temp )"
printf '%s - %s\n' "$(date +%F_%T)" "$temp"
# or echo -n "$(date) - "; get_temp
sleep 1
done | tee -a "$log"
# or just >> "$log", and tail -f the log file when you want it on screen.
tr
或者一个处理 CR -> LF 转换的实现:
exec 3<>"/dev/tcp/$host/$port"
(while echo 'read?';do sleep 1;done >&3) &
tr -d '\r' '\n' <&3 | IFS= while read temp; do
printf '%s - %s\n' "$(date +%F_%T)" "$temp"
done >> "$log"
这会在后台放置一个子 shell,每秒写入一个命令。您仍然需要一个读取循环来将当前时间格式化为接收到的行。我不知道 ^C 是否会杀死子 shell。
循环内设置的变量在循环结束后将不会出现,因为我们通过管道输入了它,如果你想尝试的话。
这是一个老问题,所以我实际上没有运行这些。可能存在语法错误或错误。但我很确定,总体想法是合理的。