シェル出力の複数のセグメントを複数の変数に分割

シェル出力の複数のセグメントを複数の変数に分割

複数のシェル結果を異なる変数に分割したいと思います。

以下は、説明するためのセンサーのサンプル出力です。

acpitz-virtual-0
Adapter: Virtual device
temp1:        +41.0°C  (crit = +95.0°C)

coretemp-isa-0000
Adapter: ISA adapter
Core 0:       +36.0°C  (high = +90.0°C, crit = +90.0°C)
Core 1:       +36.0°C  (high = +90.0°C, crit = +90.0°C)

sensorsこの場合、出力全体を含む変数(コマンド名)、 sensors_acpitz_virtual_0出力全体を含む最初のセグメント、およびsensors_coretemp_isa_00002番目のセグメントの内容を含む変数が必要です。

センサー_acpitz_virtual_0

acpitz-virtual-0
Adapter: Virtual device
temp1:        +41.0°C  (crit = +95.0°C)

Sensors_coretemp_isa_0000

coretemp-isa-0000
Adapter: ISA adapter
Core 0:       +36.0°C  (high = +90.0°C, crit = +90.0°C)
Core 1:       +36.0°C  (high = +90.0°C, crit = +90.0°C)

sensors_acpitz_virtual_0__Adapter__Virtual_device次に、最初の段落の内容のみを含む変数があります。

Adapter: Virtual device
temp1:        +41.0°C  (crit = +95.0°C)

sensors_acpitz_virtual_0__Adapter__Virtual_device__temp1acpitz-virtual-0仮想デバイスアダプタなどのtemp1温度の変数のみが含まれています。

+41.0°C  (crit = +95.0°C)

どのツールを使用する必要があります(ディストリビューションプレートにプレインストールされている一般的なツールが望ましい)、この結果をどのように取得できますか?

答え1

私は次のことをします:

eval "$(#"
  perl -MString::ShellQuote -00 -lne '
    if (/^(.+)\n(.+)/) {
      ($v1, $v2, $rest) = ("sensors_$1", "$2", $'\'');
      # $v1, $v2 contain the first 2 lines, $rest the rest

      s/\W/_/g for $v1, $v2;
      # replace non-word characters with _ in the variables

      print "$v1=" . shell_quote("$1\n$2$rest");
      print "${v1}__$v2=" . shell_quote("$2$rest");
      # output the variable definition taking care to quote the value

      while ($rest =~ /^(.*?):\s*(.*)/gm) {
        # process the "foo: bar" lines in the rest
        ($v3,$val) = ("$1", $2);
        $v3 =~ s/\W/_/g;
        print "${v1}__${v2}__$v3=" . shell_quote($val)
      }
    }' < that-file)"

-00短絡モードの場合。-lレコードの末尾から段落を除き、print出力に1つを追加します。

-n一度に1つのレコード入力を処理します。

あなたの例では、perlコマンドは次のシェルコードを出力します。

sensors_acpitz_virtual_0='acpitz-virtual-0
Adapter: Virtual device
temp1:        +41.0°C  (crit = +95.0°C)'

sensors_acpitz_virtual_0__Adapter__Virtual_device='Adapter: Virtual device
temp1:        +41.0°C  (crit = +95.0°C)'

sensors_acpitz_virtual_0__Adapter__Virtual_device__temp1='+41.0°C  (crit = +95.0°C)'

sensors_coretemp_isa_0000='coretemp-isa-0000
Adapter: ISA adapter
Core 0:       +36.0°C  (high = +90.0°C, crit = +90.0°C)
Core 1:       +36.0°C  (high = +90.0°C, crit = +90.0°C)'

sensors_coretemp_isa_0000__Adapter__ISA_adapter='Adapter: ISA adapter
Core 0:       +36.0°C  (high = +90.0°C, crit = +90.0°C)
Core 1:       +36.0°C  (high = +90.0°C, crit = +90.0°C)'

sensors_coretemp_isa_0000__Adapter__ISA_adapter__Core_0='+36.0°C  (high = +90.0°C, crit = +90.0°C)'

sensors_coretemp_isa_0000__Adapter__ISA_adapter__Core_1='+36.0°C  (high = +90.0°C, crit = +90.0°C)'

eval "$(that-perl-command)"このコマンドの出力を評価するようにシェルに指示するために使用するコード。

答え2

まあ、その名前がどこから来たのかはよくわかりません。acpitz_virtual_0__Adapter__Virtual_device__temp1来なければならないので、これは何の影響もありません。しかし、次のようになります。

sed     -e '/./{H;$!d;}' -e'x;s///' \
        -e 's/\(\n.*\)*-/_\1/g' \
        -e "s/\n\(.*\)/='\1'/" <your_input

...出力は次のとおりです。

acpitz_virtual_0='Adapter: Virtual device
temp1:        +41.0°C  (crit = +95.0°C)'
coretemp_isa_0000='Adapter: ISA adapter
Core 0:       +36.0°C  (high = +90.0°C, crit = +90.0°C)
Core 1:       +36.0°C  (high = +90.0°C, crit = +90.0°C)'

'入力に一重引用符を使用することはできません。移植可能なシェル名との唯一の非互換性は、各名前のダッシュであると思います。見積処理(もし備えて)する:

sed     -e '/./{H;$!d;}' -ex\;s/// \
        -e "s/\(\n.*\)*['-]/_\1/g" \
        -e "s/'/'"'\\&&/g'         \
        -e "s/\n\(.*\)/='\1'/" <your_input

...これは常に入力の二重引用符をエスケープします。

指定した方法でこの出力を使用するためのいくつかのオプションがあります。次のように梱包できますeval

eval "$(sed ... <your_input)"

...またはファイルに読み込むこともできます...

sed ... <your_input >out; . ./out

...またはサブシェルにストリーミングします...

sed ... <your_input | sh

...そして他の多くのこと。


sedあなたが要求した素晴らしい仕事をするもう一つの方法は次のとおりです。

sed -netDel -e'/./{H;g;s///'              \
-e'# grow'  -e's/[0-9]*:  .*\n[^:0-9]*//' \
-e'# loop'  -e's/:  .*//'                 \
-e'# ends'  -e's/[^_[:alnum:]]/_/g;}'     \
-e'# here'  -e's/\(.\)\(.*\)/& \\/p'      \
-e$\!t -ex  -e's//\2\1. \\/'              \
-e'# swap'  -e"s/'/'"'\\&&/g;tDel'        \
-ed\;:Del   -e"s/\(.*\). /'\1' /"         \
-e'# loop'  -e'/^[^:]*:  /!{p;D;}'        \
-e'# ends'  -e"s/\n/' \\\&/;P;D"  <infile >outfile       

仕組みは次のとおりです。sedある意味、ろうそくは両端に乗るものです。sedデリゲート状態左から右への繰り返しの増加と、各段落の終わりで同じ方向の繰り返しの減少との間。

良い:

1
1:2    # grow
1:2:3  # swap
  2:3  # del
    3
#if that makes any sense at all...

これ育つ間に状態が処理されます/./{H;g;...p;};$!t


  • 1つ以上の文字に一致する.各入力行に対して、コピーsedH前のスペースに追加され、次にパターンスペースが上書きgされ、予約されたすべてのスペースが即座に設定されます。

    • これにより、sed増加するスタックで編集を実行し、各反復の結果を印刷すると同時に、元の入力を常に予約済みスペースに保持することができます。
  • 内部に育つ状態では、sed各入力行に対して有効なシェル名が印刷されます。

    • sed最初の項目と最後の項目の間のすべての項目と"[0-9]*: "最後の項目の後のすべての項目を削除しますが、そうでなければ": "クラスにないすべての文字をその文字に置き換えるため、名前は再帰的に大きくなります。^[_[:alnum:]]_(そうでないまで)
  • sed testsは、プロセス中に正常に編集された行です。育つロジックを処理する前に、スクリプトでステータスを指定して分岐します。交換状態。

    • 特別なケースでは、このtestは最後の入力ライン!で実行されないため、次に落ちます。$交換ステートメントは何でも構いません。

これ交換状態処理間x;...;d


  • sedex予約済みスペースバッファの最後または空のモードスペースバッファを変更して、次の入力段落のために保存されたスペースを消去します。(そうであれば)

    • 入力に複数の空行が連続して現れることは、パターンに悪影響を及ぼさない。同じ結果を得るために、必要に応じて空白保持スペースを空のパターンスペースに置き換えることがあります。
  • sed段落の前の空白行を末尾に置き換え、スペースとバックスラッシュを追加し、一重引用符をすぐにエスケープします。(そうであれば)空白以外の保持バッファが失敗する前の段落でデルステータスを削除するか、空のdステータスを削除してください。


これデルtDel -> :Del状態はとの間で有効です:Del;...;D


  • sedすべての再帰削減モードバッファを一重引用符ペアで囲みます。

    • 最初の行が削除され、各行の最初の行が削除されます。デル繰り返されますが、最後の項目は常に独自に置き換えられます。
  • 段落バッファマッチングの場合、バッファに"^[^:]*: " sed埋め込まれたewlineが最初に発生する前に別の一重引用符が追加され、その後にスペースとバックスラッシュが追加されます。\n(そうであれば)print はPバッファの最初の行だけを出力します。

    • それ以外の場合は、sed p空でないバッファ全体を印刷します。
  • いずれにしても、残っている場合は、スクリプトの一番上にループする前に、最初にバッファに表示されるewlineを削除してくださいsedD\n

    • ここでバッファが空でない場合、スクリプトの先頭(最初の行が削除された後)で、最初のestは、実行したばかりの引用符がttrueに置き換えられたことを証明しているため、編集スクリプトのほとんどは次にsed直接スキップされます。:Del各反復のラベルデルバッファが完全に空になるまで状態です。

だからsed 最大あなたが要求した素晴らしい仕事をすることができます。sedストリーミング特性も例外ではないので、出力は次のようになります。

acpitz_virtual_0 \
acpitz_virtual_0_Adapter__Virtual_device \
acpitz_virtual_0_Adapter__Virtual_device_temp1 \
'acpitz-virtual-0
Adapter: Virtual device
temp1:        +41.0°C  (crit = +95.0°C)
' \
'Adapter: Virtual device
temp1:        +41.0°C  (crit = +95.0°C)
' \
'temp1:        +41.0°C  (crit = +95.0°C)' \
'' \
coretemp_isa_0000 \
coretemp_isa_0000_Adapter__ISA_adapter \
coretemp_isa_0000_Adapter__ISA_adapter_Core_0 \
coretemp_isa_0000_Adapter__ISA_adapter_Core_1 \
'coretemp-isa-0000
Adapter: ISA adapter
Core 0:       +36.0°C  (high = +90.0°C, crit = +90.0°C)
Core 1:       +36.0°C  (high = +90.0°C, crit = +90.0°C)
' \
'Adapter: ISA adapter
Core 0:       +36.0°C  (high = +90.0°C, crit = +90.0°C)
Core 1:       +36.0°C  (high = +90.0°C, crit = +90.0°C)
' \
'Core 0:       +36.0°C  (high = +90.0°C, crit = +90.0°C)' \
'Core 1:       +36.0°C  (high = +90.0°C, crit = +90.0°C)' \
'' \
###backslashes for set or for assignment

...各段落のスタックには:まず名前、次の値です。繰り返すことができ、各段落は空のパラメータで終わります。

これにより、より多くの検証が行われるため、入力に関係なく、誤ったシェル名や引用符のない出力値が発生する危険性はありません。

この機能は入力に対して機能します。

ineval(){
        . /dev/fd/0
        for     v
        do      case    ${#v}:${s:-$v}  in
                (0*)    until   [ 0 -eq "${#1}" ] &&
                        s= &&   ${1+"shift"}
                        do      shift;  done;;
                (*:*[-:]*) eval "s=- $1=\$v;shift"
        esac;   done
}       <<SET
        set ''  $(    sed -netDel -e'/./{H;g;s///'              \
                      -e'# grow'  -e's/[0-9]*:  .*\n[^:0-9]*//' \
                      -e'# loop'  -e's/:  .*//'                 \
                      -e'# ends'  -e's/[^_[:alnum:]]/_/g;}'     \
                      -e'# here'  -e's/\(.\)\(.*\)/& \\/p'      \
                      -e$\!t -ex  -e's//\2\1. \\/'              \
                      -e'# swap'  -e"s/'/'"'\\&&/g;tDel'        \
                      -ed\;:Del   -e"s/\(.*\). /'\1' /"         \
                      -e'# loop'  -e'/^[^:]*:  /!{p;D;}'        \
                      -e'# ends'  -e"s/\n/' \\\&/;P;D"     "$@" )
SET

あなたのコメントは次のとおりですset -x

(set -x; ineval /tmp/sens)

+ sed -netDel -e/./{H;g;s/// -e# grow -es/[0-9]*:  .*\n[^:0-9]*// -e# loop -es/:  .*// -e# ends -es/[^_[:alnum:]]/_/g;} -e# here -es/\(.\)\(.*\)/& \\/p -e$!t -ex -es//\2\1. \\/ -e# swap -es/'/'\\&&/g;tDel -ed;:Del -es/\(.*\). /'\1' / -e# loop -e/^[^:]*:  /!{p;D;} -e# ends -es/\n/' \\&/;P;D /tmp/sens
+ . /dev/fd/0
+ set  acpitz_virtual_0 acpitz_virtual_0_Adapter__Virtual_device acpitz_virtual_0_Adapter__Virtual_device_temp1 acpitz-virtual-0
Adapter: Virtual device
temp1:        +41.0°C  (crit = +95.0°C)
 Adapter: Virtual device
temp1:        +41.0°C  (crit = +95.0°C)
 temp1:        +41.0°C  (crit = +95.0°C)  coretemp_isa_0000 coretemp_isa_0000_Adapter__ISA_adapter coretemp_isa_0000_Adapter__ISA_adapter_Core_0 coretemp_isa_0000_Adapter__ISA_adapter_Core_1 coretemp-isa-0000
Adapter: ISA adapter
Core 0:       +36.0°C  (high = +90.0°C, crit = +90.0°C)
Core 1:       +36.0°C  (high = +90.0°C, crit = +90.0°C)
 Adapter: ISA adapter
Core 0:       +36.0°C  (high = +90.0°C, crit = +90.0°C)
Core 1:       +36.0°C  (high = +90.0°C, crit = +90.0°C)
 Core 0:       +36.0°C  (high = +90.0°C, crit = +90.0°C) Core 1:       +36.0°C  (high = +90.0°C, crit = +90.0°C) 
+ [ 0 -eq 0 ]
+ s=
+ shift
+ eval s=- acpitz_virtual_0=$v;shift
+ s=- acpitz_virtual_0=acpitz-virtual-0
Adapter: Virtual device
temp1:        +41.0°C  (crit = +95.0°C)

+ shift
+ eval s=- acpitz_virtual_0_Adapter__Virtual_device=$v;shift
+ s=- acpitz_virtual_0_Adapter__Virtual_device=Adapter: Virtual device
temp1:        +41.0°C  (crit = +95.0°C)

+ shift
+ eval s=- acpitz_virtual_0_Adapter__Virtual_device_temp1=$v;shift
+ s=- acpitz_virtual_0_Adapter__Virtual_device_temp1=temp1:        +41.0°C  (crit = +95.0°C)
+ shift
+ [ 0 -eq 83 ]
+ shift
+ [ 0 -eq 66 ]
+ shift
+ [ 0 -eq 41 ]
+ shift
+ [ 0 -eq 0 ]
+ s=
+ shift
+ eval s=- coretemp_isa_0000=$v;shift
+ s=- coretemp_isa_0000=coretemp-isa-0000
Adapter: ISA adapter
Core 0:       +36.0°C  (high = +90.0°C, crit = +90.0°C)
Core 1:       +36.0°C  (high = +90.0°C, crit = +90.0°C)

+ shift
+ eval s=- coretemp_isa_0000_Adapter__ISA_adapter=$v;shift
+ s=- coretemp_isa_0000_Adapter__ISA_adapter=Adapter: ISA adapter
Core 0:       +36.0°C  (high = +90.0°C, crit = +90.0°C)
Core 1:       +36.0°C  (high = +90.0°C, crit = +90.0°C)

+ shift
+ eval s=- coretemp_isa_0000_Adapter__ISA_adapter_Core_0=$v;shift
+ s=- coretemp_isa_0000_Adapter__ISA_adapter_Core_0=Core 0:       +36.0°C  (high = +90.0°C, crit = +90.0°C)
+ shift
+ eval s=- coretemp_isa_0000_Adapter__ISA_adapter_Core_1=$v;shift
+ s=- coretemp_isa_0000_Adapter__ISA_adapter_Core_1=Core 1:       +36.0°C  (high = +90.0°C, crit = +90.0°C)
+ shift
+ [ 0 -eq 157 ]
+ shift
+ [ 0 -eq 139 ]
+ shift
+ [ 0 -eq 58 ]
+ shift
+ [ 0 -eq 58 ]
+ shift
+ [ 0 -eq 0 ]
+ s=
+ shift

答え3

Perlには、「行」を段落として定義する特別な段落モードがあります。これは、1行が1つではなく2つの連続した行として定義されることを意味します\n。からman perlrun

   -0[octal/hexadecimal]
        specifies the input record separator ($/) as an octal or
        hexadecimal number. [. . .]

    The special value 00 will cause Perl to slurp files in paragraph
    mode.  

したがって、Perlスクリプトを作成して変数を印刷できます。

$ perl -00lne '/.*/; $v=$&; $v=~s/-/_/g; print "$v=\"$_\""' file 
acpitz_virtual_0="acpitz-virtual-0
Adapter: Virtual device
temp1:        +41.0°C  (crit = +95.0°C)"

coretemp_isa_0000="coretemp-isa-0000
Adapter: ISA adapter
Core 0:       +36.0°C  (high = +90.0°C, crit = +90.0°C)
Core 1:       +36.0°C  (high = +90.0°C, crit = +90.0°C)"

次に、eval次のことを伝えるシェルを使って読んでください。

$ eval "$(perl -00lne '/.*/; $v=$&; $v=~s/-/_/g; print "$v=\"$_\""' file )"
$ echo "$coretemp_isa_0000"
coretemp-isa-0000
Adapter: ISA adapter
Core 0:       +36.0°C  (high = +90.0°C, crit = +90.0°C)
Core 1:       +36.0°C  (high = +90.0°C, crit = +90.0°C)

Perlスクリプトには説明が必要な場合があります。これはコメントスクリプトと同じです。

## The . doesn't match newlines by default, so this is just a 
## quick way of getting the text before the first \n, this will be
## you variable's name.
/.*/; 
## $& is whatever was matched my the last match (//) operator. We set
## $v to that.
$v=$&; 
## Bash doesn't like dashes in variable names, this will replace
## them with underscores. 
$v=~s/-/_/g; 
## Print the variable name and its value ($foo="bar")
print "$v=\"$_\""

関連情報