我有这个ini文件的例子。我需要在两个模式Name_Z1和OBJ = Name_Z1之间提取名称,并将它们分别放在一行上。
问题是Name_Z1和OBJ = Name_Z1有多个出现,我只需要先出现。
[Name_Z5]
random;text
Names;Jesus;Tom;Miguel
random;text
OBJ=Name_Z5
[Name_Z1]
random;text
Names;Jhon;Alex;Smith
random;text
OBJ=Name_Z1
[Name_Z2]
random;text
Names;Chris;Mara;Iordana
random;text
OBJ=Name_Z2
[Name_Z1_Phone]
random;text
Names;Bill;Stan;Mike
random;text
OBJ=Name_Z1_Phone
我想要的输出是:
Jhon
Alex
Smith
我目前正在用bash编写一个更加丰富的脚本,我对此感到困惑。我更喜欢awk来完成这项工作。
我非常感谢谁能帮助我。谢谢!
对于Wintermute解决方案:[Name_Z1]部分如下所示:
[CAB_Z1]
READ_ONLY=false
FilterAttr=CeaseTime;blank|ObjectOfReference;contains;511047;512044;513008;593026;598326;CL5518;CL5521;CL5538;CL5612;CL5620|PerceivedSeverity;=;Critical;Major;Minor|ProbableCause;!=;HOUSE ALARM;IO DEVICE|ProblemText;contains;AIRE;ALIMENTA;BATER;CONVERTIDOR;DISTRIBUCION;FUEGO;HURTO;MAINS;MALLO;MAYOR;MENOR;PANEL;TEMP
NAME=CAB_Z1
[Name_Z1_Phone]部分如下所示:
[CAB_Z1_FUEGO]
READ_ONLY=false
FilterAttr=CeaseTime;blank|ObjectOfReference;contains;511047;512044;513008;593026;598326;CL5518;CL5521;CL5538;CL5612;CL5620|PerceivedSeverity;=;Critical;Major;Minor|ProbableCause;!=;HOUSE ALARM;IO DEVICE|ProblemText;contains;FUEGO
NAME=CAB_Z1_FUEGO
修复应该在" | PerceivedSeverity"
附近预期产出:
511047
512044
513008
593026
598326
CL5518
CL5521
CL5538
CL5612
CL5620
答案 0 :(得分:2)
这应该有效:
sed -n '/^\[Name_Z1/,/^OBJ=Name_Z1/ { /^Names/ { s/^Names;//; s/;/\n/g; p; q } }' foo.txt
说明:可读写,代码是
/^\[Name_Z1/,/^OBJ=Name_Z1/ {
/^Names/ {
s/^Names;//
s/;/\n/g
p
q
}
}
这意味着:在模式范围/^\[Name_Z1/,/^OBJ=Name_Z1/
中,对于与模式/^Names/
匹配的所有行,请删除开头的Names;
,然后将所有剩余的;
替换为换行,打印整个内容,然后退出。由于它会立即退出,它只会在第一个这样的模式范围内处理第一条这样的线。
sed -n '/^\[CAB_Z1/,/^NAME=CAB_Z1/ { /^FilterAttr=/ { s/^.*contains;\(.*\)|PerceivedSeverity.*$/\1/; s/;/\n/g; p; q } }' foo.txt
主要区别在于,不是从一行删除^Names
,而是替换
s/^.*contains;\(.*\)|PerceivedSeverity.*$/\1/;
已应用。这会在继续之前将部分隔离在contains;
和|PerceivedSeverity
之间。它假定该行中只有一个这样的部分。如果匹配不明确,它将选择行中最后一个匹配。
答案 1 :(得分:1)
sed -n '/\[Name_Z1\]/,/OBJ=Name_Z1$/ s/Names;//p' file.txt | tr ';' '\n'
这是sed -n
以避免打印未明确请求的任何内容。从Name_Z1开始,在OBJ = Name_Z1处结束。删除名称;并打印出现的其余部分。最后,用换行符替换分号。
答案 2 :(得分:1)
Awk解决方案
$ awk -F";" '/Name_Z1/{f=1} f && /Names/{print $2,$3,$4} /OBJ=Name_Z1/{exit}' OFS="\n" input
Jhon
Alex
Smith
或强>
$ awk -F";" '/Name_Z1/{f++} f==1 && /Names/{print $2,$3,$4}' OFS="\n" input
Jhon
Alex
Smith
-F";"
将字段分隔符设置为;
/Name_Z1/{f++}
匹配带有模式/Name_Z1/
的行如果匹配增量{f++}
f==1 && /Names/{print $2,$3,$4}
与if f == 1 and maches pattern Name with line
相同,然后打印列2 3和4(由;
分隔)
OFS="\n"
将输出字段分隔符设置为\n
新行
修改强>
$ awk -F"[;|]" '/Z1/{f++} f==1 && NF>1{for (i=5; i<15; i++)print $i}' input
511047
512044
513008
593026
598326
CL5518
CL5521
CL5538
CL5612
CL5620
答案 3 :(得分:1)
这是一组更通用的数据块组数据解决方案
这个awk
不需要结束标记,只需要开头。
awk -vRS= -F"\n" '/^\[Name_Z1\]/ {n=split($3,a,";");for (i=2;i<=n;i++) print a[i];exit}' file
Jhon
Alex
Smith
工作原理:
awk -vRS= -F"\n" ' # By setting RS to nothing, one record equals one block. Then FS is set to one line as a field
/^\[Name_Z1\]/ { # Search for block with [Name_Z1]
n=split($3,a,";") # Split field 3, the names and store number of fields in variable n
for (i=2;i<=n;i++) # Loop from second to last field
print a[i] # Print the fields
exit # Exits after first find
' file
使用更新的数据
cat file
data
[CAB_Z1_FUEGO]
READ_ONLY=false
FilterAttr=CeaseTime;blank|ObjectOfReference;contains;511047;512044;513008;593026;598326;CL5518;CL5521;CL5538;CL5612;CL5620|PerceivedSeverity;=;Critical;Major;Minor|ProbableCause;!=;HOUSE ALARM;IO DEVICE|ProblemText;contains;FUEGO
NAME=CAB_Z1_FUEGO
data
awk -vRS= -F"\n" '/^\[CAB_Z1_FUEGO\]/ {split($3,a,"|");n=split(a[2],b,";");for (i=3;i<=n;i++) print b[i]}' file
511047
512044
513008
593026
598326
CL5518
CL5521
CL5538
CL5612
CL5620
答案 4 :(得分:1)
(g)awk方式不需要一定数量的字段(虽然我假设contains;
总是在你需要名字的行上。
(g)awk '(x+=/Z1/)&&match($0,/contains;([^|]+)/,a)&&gsub(";","\n",a[1]){print a[1];exit}' f
(x+=/Z1/) - Increments x when Z1 is found. Also part of a
condition so x must exist to continue.
match($0,/contains;([^|]+)/,a) - Matches contains; and then captures everything after
up to the |. Stores the capture in a. Again a
condition so must succeed to continue.
gsub(";","\n",a[1]) - Substitutes all the ; for newlines in the capture
group a[1].
{print a[1];exit}' - If all conditions are met then print a[1] and exit.
这种方式适用于(m)awk
awk '(x+=/Z1/)&&/contains/{split($0,a,"|");y=split(a[2],b,";");for(i=3;i<=y;i++)
print b[i];exit}' file
答案 5 :(得分:0)
以下awk
脚本将执行您想要的操作:
awk 's==1&&/^Names/{gsub("Names;","",$0);gsub(";","\n",$0);print}/^\[Name_Z1\]$/||/^OBJ=Name_Z1$/{s++}' inputFileName
更详细:
s==1 && /^Names;/ {
gsub ("Names;","",$0);
gsub(";","\n",$0);
print
}
/^\[Name_Z1\]$/ || /^OBJ=Name_Z1$/ {
s++
}
状态s
以零值开头,并且只要您找到两行中的一行,就会递增:
[Name_Z1]
OBJ=Name_Z1
这意味着,在这些行的第一组之间,s
将等于一。这是其他条件的来源。当s
为1并且您找到以Names;
开头的行时,您会进行两次替换。
第一种是摆脱前面的Names;
,第二种是用换行符替换所有;
分号字符。然后你打印出来。
您的测试数据的输出正如预期的那样:
Jhon
Alex
Smith