我有一个名为“SAMPLE.txt”的文件,其内容如下,
P1
10,9:6/123456
P2
blah blah
P1
10,9:5/98765
P2
blah
blah
P1
blah blah
P2
我想要一个输出文件“RESULT.txt”,
Value1:123456
Value2:98765
Value3:NULL
我需要先获取 P1 和 P2 部分之间的内容,然后找到 10,9*/ 的值,并将其保存为另一个值。如果某个 P1-P2 块不包含此值,我想将其保存为“NULL”。
如何在 shell/awk 中编写上述代码?
我对脚本编写很陌生。
答案1
这有效并且完全可移植:
sed '\|^P1.*|!d;s||Value:|
:n
N;\|\nP2|!bn
s|:.*\n10,9[^/]*/|:|
s|\n.*||;s|:$|:NULL|'
流程如下:
首先它寻址
^
以P1
如果当前行
!
不匹配,则会d
将其删除。如果是,则替换
P1
为Value:
然后它设置
:n
ext 标签并拉入N
ext 行。如果
\nP2
没有!
找到,则b
返回到:n
ext 标签并重复尝试,直到出现为止。然后,它会删除
:.*\n10,9
直到第一个出现的/
字符为止的所有出现的字符。它删除第一个
\n
可用的 ewline 和所有后续字符。如果最后一个字符是
:
后面的冒号,Value
则插入字符串NULL
。
第 6 步和第 7 步使它起作用 - 在第 6 步中,它删除了\n
所需数字字符串之前的 ewline,但如果不存在,那么下一个\n
ewline 将是紧随其后的那一行Value:
,因此一切进入步骤 7。
这是在行动中:
sed '\|^P1.*|!d;s||Value:|
:n
N;\|\nP2|!bn
s|:.*\n10,9[^/]*/|:|
s|\n.*||;s|:$|:NULL|' <<\DATA
P1
10,9:6/123456
P2
blah blah
P1
10,9:5/98765
P2
blah
blah
P1
blah blah
P2
DATA
输出:
Value:123456
Value:98765
Value:NULL
答案2
使用perl
(尽管将整个文件放入内存中):
perl -0777 -ne 'while (/P1\n(.*?)\nP2/gs) {
printf "Value%d:%s\n", ++$n, $1 =~ /^10,9.*\// ? $'\'': "NULL"}'
答案3
一个perl
办法:
$ perl -F'/' -alne '
if (/P1/../P2/ and $_ !~ /^P/) {
print "Value@{[++$i]}:",$F[1]?$F[1]:"NULL";
}
' file
Value1:123456
Value2:98765
Value3:Null
解决方案awk
:
$ awk -F'/' '/P2/{f=0};/P1/{f=1;next};f{print "Value"++i":"($2?$2:"Null")}' file
Value1:123456
Value2:98765
Value3:Null
答案4
非常感谢大家。这是最终解决我的问题的一段代码。
nawk -v fname="${filename}" -F '/|:' '
function isnum(x){return(x==x+0)}
/P1/,/P3/{
# Found start increment i reset variables go to next line
if(/P1/){
++i
fid =""
count++
next
}
# Found end validate variable and print go to next line
if(/P3/){
printf "%s|",count
printf "%s|",isnum(fid)?fid:"NULL"
next
}
if(!fid && /36,59:*/)
{
fid = $NF
}
' ${filename} >>output.txt
但现在我遇到了另一个问题,我为此创建了一个单独的线程。
如果你们能帮忙的话,这是链接。