여러 개의 쉘 결과를 서로 다른 변수로 분할하고 싶습니다.
다음은 설명하기 위한 센서의 샘플 출력입니다.
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
두 번째 세그먼트의 내용을 포함하는 변수를 갖고 싶습니다 .
센서_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
출력에 하나를 추가합니다.
-n
한 번에 하나의 레코드 입력을 처리합니다.
귀하의 예에서 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
.
하나 이상의 문자와 일치하는
.
각 입력 줄 에 대해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
- 여기에서 버퍼가 비어 있지 않으면 스크립트 상단(첫 번째 줄이 제거된 후)에서 초기
t
est는 방금 수행한 인용문이 true로 대체되었음을 증명하므로 편집 스크립트의 대부분은 다음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에는 "줄"을 단락으로 정의하는 특수 단락 모드가 있습니다. 이는 한 줄이 하나가 아닌 두 개의 연속된 줄로 정의됨을 의미합니다 \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=\"$_\""