複数のシェル結果を異なる変数に分割したいと思います。
以下は、説明するためのセンサーのサンプル出力です。
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_0000
2番目のセグメントの内容を含む変数が必要です。
センサー_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__temp1
acpitz-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つ以上の文字に一致する
.
各入力行に対して、コピーsed
がH
前のスペースに追加され、次にパターンスペースが上書きg
され、予約されたすべてのスペースが即座に設定されます。- これにより、
sed
増加するスタックで編集を実行し、各反復の結果を印刷すると同時に、元の入力を常に予約済みスペースに保持することができます。
- これにより、
内部に育つ状態では、
sed
各入力行に対して有効なシェル名が印刷されます。sed
最初の項目と最後の項目の間のすべての項目と"[0-9]*: "
最後の項目の後のすべての項目を削除しますが、そうでなければ": "
クラスにないすべての文字をその文字に置き換えるため、名前は再帰的に大きくなります。^
[_[:alnum:]]
_
(そうでないまで)。
sed
t
estsは、プロセス中に正常に編集された行です。育つロジックを処理する前に、スクリプトでステータスを指定して分岐します。交換状態。- 特別なケースでは、この
t
estは最後の入力ライン!
で実行されないため、次に落ちます。$
交換ステートメントは何でも構いません。
- 特別なケースでは、この
これ交換状態処理間x;...;d
sed
ex
予約済みスペースバッファの最後または空のモードスペースバッファを変更して、次の入力段落のために保存されたスペースを消去します。(そうであれば)。- 入力に複数の空行が連続して現れることは、パターンに悪影響を及ぼさない。同じ結果を得るために、必要に応じて空白保持スペースを空のパターンスペースに置き換えることがあります。
sed
段落の前の空白行を末尾に置き換え、スペースとバックスラッシュを追加し、一重引用符をすぐにエスケープします。(そうであれば)空白以外の保持バッファが失敗する前の段落でデルステータスを削除するか、空のd
ステータスを削除してください。
これデルtDel -> :Del
状態はとの間で有効です:Del;...;D
。
sed
すべての再帰削減モードバッファを一重引用符ペアで囲みます。- 最初の行が削除され、各行の最初の行が削除されます。デル繰り返されますが、最後の項目は常に独自に置き換えられます。
段落バッファマッチングの場合、バッファに
"^[^:]*: "
sed
埋め込まれたewlineが最初に発生する前に別の一重引用符が追加され、その後にスペースとバックスラッシュが追加されます。\n
(そうであれば)print はP
バッファの最初の行だけを出力します。- それ以外の場合は、
sed
p
空でないバッファ全体を印刷します。
- それ以外の場合は、
いずれにしても、残っている場合は、スクリプトの一番上にループする前に、最初にバッファに表示されるewlineを削除してください
sed
。D
\n
- ここでバッファが空でない場合、スクリプトの先頭(最初の行が削除された後)で、最初のestは、実行したばかりの引用符が
t
trueに置き換えられたことを証明しているため、編集スクリプトのほとんどは次にsed
直接スキップされます。:Del
各反復のラベルデルバッファが完全に空になるまで状態です。
- ここでバッファが空でない場合、スクリプトの先頭(最初の行が削除された後)で、最初のestは、実行したばかりの引用符が
だから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=\"$_\""