简体   繁体   English

RPi:第一行之后读取循环失败时的Bash脚本

[英]RPi: Bash script while read loop fails after first line

I recently bought a Slice of Radio - https://www.wirelessthings.net/slice-of-radio-wireless-rf-transciever-for-the-raspberry-pi , which I connected to my serial port in an RPi with Raspbian. 我最近买了收音机的一个切片- https://www.wirelessthings.net/slice-of-radio-wireless-rf-transciever-for-the-raspberry-pi ,我连接到我的串口与Raspbian的RPI 。

I have a temperature+humidity sensor which connects to the Slice of Radio and periodically sends a string of characters with several information, which can be read in the RPi from the serial port (/dev/ttyAMA0). 我有一个温度+湿度传感器,它连接到无线电广播,并定期发送带有多个信息的字符串,这些信息可以从串行端口(/ dev / ttyAMA0)的RPi中读取。

To read this information and make use of it, I decided to write a Bash script. 为了阅读和利用这些信息,我决定编写一个Bash脚本。 This information is transmitted concatenated with 12-char strings and each string always starts with a fixed set of characters (in the case, aSD). 该信息以12个字符的字符串连接在一起,并且每个字符串始终以固定的字符集(在这种情况下为aSD)开头。

This Bash script is supposed to be running in an infinite loop, to make sure that all the information that is sent periodically, is captured and processed as it should. 该Bash脚本应该在无限循环中运行,以确保定期捕获的所有信息均应被捕获和处理。

For that purpose, the following small script works properly: 为此,以下小脚本可以正常工作:

    #!/bin/bash
    IFS='aSD'
    while read -r -n 12 char1 char2 char3 char4 char5
    do
    date=`/bin/date -u +%F@%X`
    echo $date
    echo  "1= ""$char1"
    echo  "2= ""$char2"
    echo  "3= ""$char3"
    echo  "4= ""$char4"
    echo  "5= ""$char5"
    done < /dev/ttyAMA0

and outputs the following (every line 4 is the information I need): 并输出以下内容(每行4是我需要的信息):

    2016-02-13@23:06:12
    1= 
    2= 
    3= 
    4= RHUM77.0-
    5= 
    2016-02-13@23:06:12
    1= 
    2= 
    3= 
    4= TEMP20.0-
    5= 
    2016-02-13@23:11:08
    1= 
    2= 
    3= 
    4= RHUM77.0-
    5= 
    2016-02-13@23:11:08
    1= 
    2= 
    3= 
    4= TEMP19.9-
    5= 
    2016-02-13@23:11:08
    1= 
    2= 
    3= 
    4= BATT3.32-
    5= 
    2016-02-13@23:11:08
    1= 
    2= 
    3= 
    4= 
    5= LEEPING-

Still then, if I run the following script (a simplified version of mine): 即使如此,如果我运行以下脚本(我的简化版本):

    !/bin/bash
    log_file="/home/pi/logs/Temp_$(date +%Y%m%d).log"
    log_file_copy="/home/pi/logs/Temp_$(date +%Y%m%d)_copy.log"
    sensor="/home/pi/sensor"

    IFS='aSD'
    while read -r -n 12 char1 char2 char3 value char5
    do
    date=`/bin/date -u +%F@%X`
    msgid=$( /bin/echo $value | cut -c1-4 )
    echo $msgid
    if [ "$msgid" = "TEMP" ]; then

    #Write current temperature to log file
    log=`/bin/date -u +%F@%X`
    log+=" | Current Temperature: "
    temp=$( /bin/echo $value | cut -c5-8 )
    log+=$temp
    log+=" ºC"
    /bin/echo $log>>$log_file
    elif [ "$msgid" = "RHUM" ]; then

    #If log file backup still exists, start by deleting it
    if [ -f "$log_file_copy" ]; then
            /bin/rm $log_file_copy > /dev/null 2>&1 &
    fi
    #If log file already exists, start by creating a backup
    if [ -f "$log_file" ]; then
            /bin/mv $log_file $log_file_copy > /dev/null 2>&1 &
    fi

    #Write current relative humidity to log file
    log=`/bin/date -u +%F@%X`
    log+=" | Current Relative Humidity: "
    rhum=$( /bin/echo $value | cut -c5-8 ) 
    log+=$rhum
    log+=" %"
    /bin/echo $log>>$log_file
    elif [ "$msgid" = "BATT" ]; then

    #Write current battery voltage to log file
    log=`/bin/date -u +%F@%X`
    log+=" | Current Battery Voltage: "
    volt=$( /bin/echo $value | cut -c5-8 )
    if [ "$volt" != "LOW-" ]; then
            volt="LOW"
            log+=$volt
    else
            log+=$volt
            log+=" V"
    fi
    /bin/echo $log>>$log_file
    fi

    #Store values to display in website - personal.xively.com
    time=`/bin/date -u +%FT%XZ`
    if [ -n "$temp" ]; then
    /bin/echo "$time,$temp">>/home/pi/cosm/sensor/temperature/cosm.csv
    fi
    if [ -n "$rhum" ]; then
    /bin/echo "$time,$rhum">>/home/pi/cosm/sensor/humidity/cosm.csv
    fi
    if [ -n "$volt" ]; then
    /bin/echo "$time,$volt">>/home/pi/cosm/sensor/voltage/cosm.csv
    fi
    /bin/bash /home/pi/cosm/sensor/upload-cosm.sh > /dev/null 2>&1 &
    log=`/bin/date -u +%F@%X`
    log+=" | Values sent to xively.com"
    /bin/echo $log>>$log_file

    done < /dev/ttyAMA0

This is all that it processes: 这就是它处理的全部内容:

    RHUM
    RHUM
    RHUM

If I take out the last block of code (to send the values to xively.com), it shows (which is what I need): 如果我取出最后一块代码(将值发送到xively.com),它将显示(这是我需要的):

    RHUM
    TEMP
    RHUM
    TEMP
    RHUM
    TEMP

I've spent a lot of time trying to find out why doesn't the loop go through all the records and only processes the first one. 我花了很多时间试图找出循环为什么不遍历所有记录而只处理第一个记录。

Can anyone shed a light or provide any working alternative? 任何人都可以阐明或提供其他可行的选择吗?

Thanks in advance for any help. 在此先感谢您的帮助。

I edited the script for clarity, and ran it against input I made based on your first set of output. 为了清晰起见,我编辑了脚本,并根据我根据第一组输出所做的输入来运行脚本。 I don't think the loop skipped records - perhaps the input didn't match what you expected. 我认为循环不会跳过记录-也许输入与您期望的不匹配。 The version below captures the raw data to a file, so you can verify the outcomes against the raw data. 下面的版本将原始数据捕获到文件中,因此您可以根据原始数据验证结果。

#!/bin/bash

PATH=/bin:/usr/bin

log_file="/home/pi/logs/Temp_$(date +%Y%m%d).log"
log_file_raw=${log_file/./_raw.}

while read -r -n 12 dozen
do
    echo -n "$dozen" >> $log_file_raw

    date=`date -u +%F@%X`
    key=${dozen:3:4}
    val=${dozen:7}
    val=${val%-}

    case $key in
    TEMP)
        log="$date | Current Temperature: $val ºC"
        csv=/home/pi/cosm/sensor/temperature/cosm.csv
    ;;
    RHUM)
        log="$date | Current Relative Humidity: $val %"
        csv=/home/pi/cosm/sensor/humidity/cosm.csv
    ;;
    BATT)
        log="$date | Current Battery Voltage: $val V"
        csv=/home/pi/cosm/sensor/voltage/cosm.csv
    ;;
    *)
        continue
    ;;
    esac

    echo "$log" >> $log_file
    echo "${date/@/T}Z,$val" >> $csv

    /bin/bash /home/pi/cosm/sensor/upload-cosm.sh > /dev/null 2>&1 &
    echo "$date | Values sent to xively.com" >> $log_file

done < /dev/ttyAMA0

exit 0

One important change is that this script does not alter IFS. 一个重要的变化是该脚本不会更改IFS。 Each character of IFS is a separator. IFS的每个字符都是一个分隔符。 A good example of this is the LEEPING- for char5 when the input was (presumably) aSDSLEEPING- . 的一个很好的例子是LEEPING-为char5当输入为(大概) aSDSLEEPING- Instead, this script uses the builtin bash substring feature of parameter expansion. 而是,此脚本使用参数扩展的内置bash子字符串功能。

I left out the log rotation, because I want to suggest you log to syslog over the long term. 我省略了日志轮换,因为我想建议您长期登录到syslog。 The logger command will send a message to syslog. logger命令将向syslog发送一条消息。 On most systems those logs are already rotated on a regular basis. 在大多数系统上,这些日志已定期轮换。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM