2016-02-14 30 views
0

我最近買了一個無線電片 - https://www.wirelessthings.net/slice-of-radio-wireless-rf-transciever-for-the-raspberry-pi,我連接到我的串行端口在RPi與Raspbian。RPi:Bash腳本while讀取循環失敗後第一行

我有一個溫度+溼度傳感器,它連接到無線電切片並週期性地發送一串帶有幾個信息的字符,這些信息可以通過串口(/ dev/ttyAMA0)在RPi中讀取。

要閱讀這些信息並使用它,我決定編寫一個Bash腳本。該信息與12個字符的字符串串聯傳輸,每個字符串始終以一組固定的字符開始(在這種情況下,aSD)。

此Bash腳本應該在無限循環中運行,以確保定期發送的所有信息都被捕獲並按照它應該進行處理。

爲此,下面的小腳本工作正常:

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

和輸出以下(每行4是我需要的信息):

[email protected]:06:12 
    1= 
    2= 
    3= 
    4= RHUM77.0- 
    5= 
    [email protected]:06:12 
    1= 
    2= 
    3= 
    4= TEMP20.0- 
    5= 
    [email protected]:11:08 
    1= 
    2= 
    3= 
    4= RHUM77.0- 
    5= 
    [email protected]:11:08 
    1= 
    2= 
    3= 
    4= TEMP19.9- 
    5= 
    [email protected]:11:08 
    1= 
    2= 
    3= 
    4= BATT3.32- 
    5= 
    [email protected]:11:08 
    1= 
    2= 
    3= 
    4= 
    5= LEEPING- 

儘管如此那麼,如果我跑以下腳本(我的簡化版):

!/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 +%[email protected]%X` 
    msgid=$(/bin/echo $value | cut -c1-4) 
    echo $msgid 
    if [ "$msgid" = "TEMP" ]; then 

    #Write current temperature to log file 
    log=`/bin/date -u +%[email protected]%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 +%[email protected]%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 +%[email protected]%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 +%[email protected]%X` 
    log+=" | Values sent to xively.com" 
    /bin/echo $log>>$log_file 

    done < /dev/ttyAMA0 

這就是它的全部過程ES:

RHUM 
    RHUM 
    RHUM 

如果我拿出代碼的最後一塊(送值xively.com),它顯示了(這是我所需要的):

RHUM 
    TEMP 
    RHUM 
    TEMP 
    RHUM 
    TEMP 

我花很多時間試圖找出爲什麼循環不會遍歷所有記錄,只處理第一個記錄。

任何人都可以擺脫光線或提供任何工作替代?

在此先感謝您的幫助。

+0

你能顯示原始輸入嗎?當你說「這是它所處理的一切」時 - 你的意思是'RHUM'是輸出嗎? 「它顯示我需要什麼」 - 你能具體說明你需要什麼嗎? – dancancode

+0

RHUM是第一行的輸出,因爲這只是我在程序中使用的ECHO的結果。TEMP是第二行的輸出,所以我期望它在RHUM之後出現。基本上,我需要它處理每12個字符作爲一條線...... – user5923286

回答

1

爲了清晰起見,我編輯了腳本,並根據第一組輸出製作的輸入對它進行了編輯。我不認爲循環會跳過記錄 - 可能輸入與您的預期不符。以下版本將原始數據捕獲到文件中,以便您可以根據原始數據驗證結果。

#!/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 +%[email protected]%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 

一個重要的變化是該腳本不會改變IFS。 IFS的每個角色都是分隔符。一個很好的例子是當輸入爲(假定)爲aSDSLEEPING-時char15的LEEPING-。相反,此腳本使用參數擴展的內置bash子字符串功能。

我忘了日誌輪換,因爲我想建議您長期登錄syslog。 logger命令將向syslog發送消息。在大多數系統中,這些日誌已經定期輪換。

+0

您的建議完美地工作:從IFS移動使用參數擴展的內置bash子字符串功能絕對是絕招。我還有一個問題需要考慮:我不知道在每次迭代中發送的字符總數(可以是24 - RHUM和TEMP或更多 - RHUM,TEMP,BATT),有沒有辦法確定我何時到達字符串的結尾,爲了能夠知道我對該行的處理已完成? – user5923286

+0

根據猜測(我沒有其中之一),如果您進行了單次讀取而沒有大小限制,則會消耗當時可用的所有字符。然後,您可以使用for循環來操作每個字符,例如'while read -r buf;爲((i = 0; i <$ {#buf}; i + = 12));做echo $ {buf:i:12};完成;完成 dancancode

+0

不幸的是,在/ dev/ttyAMA0上運行'read -r'並沒有完成(從我使用'bash -x'運行腳本所能理解的內容),所以你的例子不會產生任何數據。任何其他想法? – user5923286

相關問題