我在基于 Linux 的 Synology 平台上有以下字符串,我想提取一些值:
{"report":"Instantaneous values:<BR>voltage=243.5 Vrms<BR>FFTComponents:<BR>Phase 1:<BR>\tcurrent=0.348 A, activePower=68.461 W, reactivePower=50.175 var, apparentPower=84.879 VA, cosfi=80, quadrant=0, phaseshift=0.0, phaseDiff=0.0<BR>\tFFTComponents:<BR>Phase 2:<BR>\tcurrent=0.076 A, activePower=2.888 W, reactivePower=18.492 var, apparentPower=18.717 VA, cosfi=10, quadrant=0, phaseshift=0.0, phaseDiff=0.0<BR>\tFFTComponents:<BR>Phase 3:<BR>\tcurrent=1.431 A, activePower=299.807 W, reactivePower=177.96 var, apparentPower=348.646 VA, cosfi=85, quadrant=0, phaseshift=0.0, phaseDiff=0.0<BR>\tFFTComponents:<BR><BR><BR>Phase 1, peak active power 5570.098 W at 03/09/2022 14:18:10<BR>Phase 2, peak active power
4562.172 W at 25/09/2022 09:21:45<BR>Phase 3, peak active power 3188.103 W at 07/11/2022 16:35:35<BR>active energy RMS per phase mapping combination<BR>phase mapping 210=372.779 kWh [ 1/1]<BR>phase mapping 12=808.956 kWh [* 1/3]<BR>phase mapping 21=307.154 kWh [
-1/1]<BR>phase mapping 102=321.293 kWh [ -1/2]<BR>phase mapping 120=508.832 kWh [ 1/0]<BR>phase mapping 201=317.701 kWh [
-1/1]<BR><BR>active energy RMS (solar) per phase mapping combination<BR>phase mapping 210=0.0 kWh [ 1/1]<BR>phase mapping 12=0.0 kWh [* 1/3]<BR>phase mapping 21=0.0 kWh [ -1/1]<BR>phase mapping 102=0.0 kWh [ -1/2]<BR>phase mapping 120=0.0 kWh [ 1/0]<BR>phase mapping 201=0.0 kWh [ -1/1]<BR><BR>"}
我在互联网上找到了一些代码。该代码有效,但是,它没有提供我想要的所有信息。
https://github.com/apazga/smappee-domoticz-bash/blob/master/smappee_bash_extractor.sh
代码部分用于sed
查找字符串urrent=
,并返回该字符串后面的值。
AMPS=`echo $SMAP |sed -e 's|.*urrent=\(.*\)|\1|' -e 's|\(.\{1,4\}\).*|\1|'`
我想将其分为 AMPSL1、AMPSL2 和 AMPSL3
- AMPL1:必须搜索 current 的第一次出现并返回 0.348
- AMPL2:必须搜索 current 的第二次出现并返回 0.076
- AMPL3:必须搜索 current 的第三次出现并返回 1.431
我已经发现以下代码返回最后一次出现的情况
AMPSL3=`echo $SMAP |sed -e '$s|.*urrent=\(.*\)|\1|' -e 's|\(.\{1,4\}\).*|\1|'`
有人可以帮我吗?
答案1
正则表达式的问题是它们无法计数。因此,对于要提取的每个值,您需要一个不同的、复杂的正则表达式。相反,我会使用grep
beforesed
来隔离所需的值:
$ AMPS=$(echo "$SMAP" | grep -oE 'current=[0-9]+\.[0-9]+' | sed -E 's|current=||')
$ echo "$AMPS"
0.348
0.076
1.431
head
然后可以使用和的组合tail
来提取各个值。
$ AMPSL1=$(echo "$AMPS" | head -1)
$ echo $AMPSL1
0.348
$ AMPSL2=$(echo "$AMPS" | tail +2 | head -1)
$ echo $AMPSL2
0.076
$ AMPSL3=$(echo "$AMPS" | tail +3 | head -1)
$ echo $AMPSL3
1.431
或者正如 terdon 所建议的,“如果使用的话,你可以避免双头/尾awk
”。
$ AMPSL2=$(echo "$AMPS" | awk 'NR==2')
$ echo $AMPSL2
0.076
答案2
如果您有 GNU grep
(在嵌入式系统上可能没有),您可以这样做:
read ampl1 ampl2 ampl3 < <(grep -oP 'current=\K[0-9.]+' <<<"$amps" | tr '\n' ' ' | sed 's/$/\n/' )
该习惯用法允许您使用进程替换将read var < <(command)
的输出保存command
到当前 shell 中的变量中。var
这是用于grep -o
仅打印输入的匹配部分,-P
对于 PCRE 正则表达式,它为我们提供了\K
“忘记此处之前匹配的所有内容”的符号。然后,我们需要将空格转换为换行符,tr
并添加尾随换行符,以sed
准备好将所有内容传递给read
存储到变量中的内置函数。输出是:
$ read ampl1 ampl2 ampl3 < <(grep -oP 'current=\K[0-9.]+' <<<"$amps" | tr '\n' ' ' | sed 's/$/\n/' )
$ echo "AMPL1: $ampl1 AMPL2: $ampl2 AMPL3: $ampl3"
AMPL1: 0.348 AMPL2: 0.076 AMPL3: 1.431
如果你不能使用grep -oP
,你可以这样做:
$ read ampl1 ampl2 ampl3 < <(perl -007 -ne '@m=(/current=([0-9.]+)/g); print "@m\n"' a)
$ echo "AMPL1: $ampl1 AMPL2: $ampl2 AMPL3: $ampl3"
AMPL1: 0.348 AMPL2: 0.076 AMPL3: 1.431
这个答案需要你使用bash
shell。由于 Synology 系统上的默认 shell 是以bash
POSIX 模式运行的 shell,因此<(...)
不启用进程替换 ( )。您必须首先bash
简单地输入bash
。
或者,如果您将在脚本中使用这些命令,请使用bash scriptName.sh
.