【问题标题】:Linux - parsing data, what language to useLinux——解析数据,使用什么语言
【发布时间】:2014-06-18 02:49:18
【问题描述】:

我希望从基于“列”的格式中解析数据。我遇到了一些问题,我觉得我正在“破解”bash/awk 命令来提取字符串和数字。如果数字/文本以不同的格式出现,则脚本可能会意外失败,并且会出现错误。

数据:

RSSI (dBm):    -86      Tx Power:    0
RSRP (dBm):    -114     TAC:         4r5t (12341)
RSRQ (dB):     -10      Cell ID:     efefwg (4261431)
SINR (dB):      2.2

我的方法:

使用 bash 和 awk

#!/bin/bash

DATA_OUTPUT=$(get_data)

RSSI=$(echo "${DATA_OUTPUT}" | awk '$1 == "RSSI" {print $3}')
RSRP=$(echo "${DATA_OUTPUT}" | awk '$1 == "RSRP" {print $3}')
RSRQ=$(echo "${DATA_OUTPUT}" | awk '$1 == "RSRQ" {print $3}')
SINR=$(echo "${DATA_OUTPUT}" | awk '$1 == "SINR" {print $3}')
TX_POWER=$(echo "${DATA_OUTPUT}" | awk '$4 == "Tx" {print $6}')

echo "$SINR"
echo ">$SINR<"

但是上面的输出结果很奇怪。

2.2   # thats fine!
<2.2  # what??? expecting >4.6<

像这样的小事情让我对使用 awk 和 bash 解析数据产生疑问。我应该使用 C++ 还是其他语言?或者有更好的方法吗?

谢谢

【问题讨论】:

  • 我无法重现该问题。另外,您的问题到底是什么,打印&lt;$var&gt; 或解析数据或两者兼而有之?
  • 您熟悉哪些语言?你在什么环境工作(什么样的数据?上面的简单数据,数据库中的大量数据,科学数据等)。这有助于更好地回答您的问题。
  • 您可能还想通过programmers.stackexchange.com 提出您的问题,这似乎更适合解决如此广泛的问题。
  • 您应该echo $DATA_OUTPUT 以确保它包含您所期望的内容。
  • 另外,请确保您的示例正确:未提供get_data(我使用了cat $1),您的输出应该是2.2,而不是4.6(参见输入)。就目前而言,就像上面的 JS 一样,我无法重现您的结果。

标签: linux bash parsing awk


【解决方案1】:

这应该是您的起点(如果您的输入数据是制表符分隔或固定宽度的字段,则可以简化或删除match()):

$ cat file
RSSI (dBm):    -86      Tx Power:    0
RSRP (dBm):    -114     TAC:         4r5t (12341)
RSRQ (dB):     -10      Cell ID:     efefwg (4261431)
SINR (dB):      2.2

.

$ cat tst.awk
{
    tail = $0
    while ( match(tail,/[^:]+:[[:space:]]+[^[:space:]]+[[:space:]]*([^[:space:]]*$)?/) )
    {
        nvPair = substr(tail,RSTART,RLENGTH)
        sub(/ \([^)]+\):/,":",nvPair)           # remove (dB) or (dBm)
        sub(/:[[:space:]]+/,":",nvPair)         # remove spaces after :
        sub(/[[:space:]]+$/,"",nvPair)          # remove trailing spaces
        split(nvPair,tmp,/:/)
        name2value[tmp[1]] = tmp[2]             # name2value["RSSI"] = "-86"
        tail = substr(tail,RSTART+RLENGTH)
    }
}

END {
    for (name in name2value) {
        value = name2value[name]
        printf "%s=\"%s\"\n", name, value
    }
}

.

$ awk -f tst.awk file
Tx Power="0"
RSSI="-86"
TAC="4r5t (12341)"
Cell ID="efefwg (4261431)"
RSRP="-114"
RSRQ="-10"
SINR="2.2"

希望很明显,在上面的脚本中 match() 循环之后,您可以简单地说出 print name2value["Tx Power"] 之类的内容来打印该关键短语的值。

如果您的数据是在 DOS 中创建的,请先对其运行 dos2unixtr -d '^M',其中 ^M 表示文字 control-M 字符。

【讨论】:

    【解决方案2】:

    您的数据包含 DOS 样式的 \r\n 行尾。当你这样做时

    echo ">$SINR<"
    

    实际输出其实是

    >4.6\r<
    

    回车将光标返回到行首。

    你可以这样做:

    DATA_OUTPUT=$(get_data | sed 's/\r$//')
    

    但不是一遍又一遍地解析输出,我会这样重写:

    while read -ra fields; do
        case ${fields[0]} in
            RSSI) rssi=${fields[2]};;
            RSRP) rsrp=${fields[2]};;
            RSPQ) rspq=${fields[2]};;
            SINR) sinr=${fields[2]};;
        esac
        if [[ ${fields[3]} == "Tx" ]]; then tx_power=${fields[5]}; fi
    done < <(get_data | sed 's/\r$//' )
    

    【讨论】:

    • 出现语法错误:重定向意外。也试图理解,所以我可以修复它
    • 此脚本使用 bash 特定功能,因此请勿使用 sh scriptname 调用它
    • sed 's/\r$//' 命令必须在每个变量上调用,而不仅仅是整个数据。所以我会改变它来合并它。感谢您的脚本。
    • while 循环从process substitution 读取——这基本上意味着 bash 可以像读取文件一样读取管道。
    • 我不明白你的 sed 评论是什么意思。您需要从数据中删除回车,并且只需要这样做一次。
    猜你喜欢
    • 1970-01-01
    • 2019-02-16
    • 2019-10-14
    • 2010-10-09
    • 2019-10-27
    • 1970-01-01
    • 1970-01-01
    • 2015-07-03
    • 2014-03-04
    相关资源
    最近更新 更多