sedはN番目のエントリを探します。

sedはN番目のエントリを探します。

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:電流の最初の発生を検索し、0.348を返す必要があります。
  • AMPL2:2番目に現れる電流を検索し、0.076を返す必要があります。
  • AMPL3:3番目に現れる電流を検索し、1.431を返す必要があります。

最後の発生を返す次のコードが見つかりました。

  AMPSL3=`echo $SMAP |sed -e '$s|.*urrent=\(.*\)|\1|' -e 's|\(.\{1,4\}\).*|\1|'`

誰でも私を助けることができますか?

答え1

正規表現の問題は数えられないことです。したがって、抽出する各値に対して異なる複雑な正規表現が必要です。代わりに必要な値を分離するためにgrepbeforeを使用してください。sed

$ 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現在のシェルの変数に保存できます。var

grep -oこれは入力の一致部分のみを印刷するために使用され、PCRE正規表現の場合は「ここで以前に一致したすべての項目を忘れてしまう」という表記を-P提供します。\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この回答ではシェルを使用する必要があります。 SynologyシステムのデフォルトシェルはbashPOSIXモードで実行されるシェルであるため、<(...)プロセスの交換()は有効になりません。最初にbash入力する必要がありますbash

または、スクリプトでこれらのコマンドを使用するには、を使用しますbash scriptName.sh

関連情報