我想为每个具有"标题行"的块找到$ 3列的最小值。格式为' @ value1 value2'。该文件看起来像这样
@ 62.65 -50.35
0 1.50 1.676
1.67 1.50 1.677
1.67 2.25 1.423
2.90 2.25 2.902
2.90 4.95 2.903
3.04 4.95 3.049
@ 63.61 -50.45
0 1.50 1.654
3.42 1.50 1.875
3.43 2.19 3.430
5.31 2.19 1.032
5.32 6.23 5.320
5.43 6.23 5.434
在此之后,我想打印标题以及最小$ 3的整行。
所以,我的输出文件看起来应该是
@ 62.65 -50.35
1.67 2.25 1.423
@ 63.61 -50.45
5.31 2.19 1.032
这是我到目前为止所尝试的:
awk '{if (!/^@/) {if ($3 < min) {$3=min;} print $1, $2, $3, min; min = $3;} else if (/^@/) min = 10; print $1 $2 $3;}' input.txt > output.txt
我有麻烦将块分开并重置&#34;重置&#34; min(我试图将&#39; start&#39;值设置为高 - 即10)。
我是编程新手,到目前为止主要使用awk - 如果你可以帮助我,那真的很棒!非常感谢!干杯,Isi
答案 0 :(得分:3)
使用awk:
awk '/^@/{if(h){print h RS m}min=""; h=$0; next}min=="" || $3 < min{min=$3; m=$0}END{print h RS m}' infile
使用array
awk '/^@/{h=$0;min="";next}min==""||$3<min{min=$3;l[h]=$0}END{for(i in l)print i RS l[i]}' infile
更好的可读性:
awk '/^@/{
if(h){
print h RS m
}
min=""; h=$0; next
}
min=="" || $3 < min{
min=$3;
m=$0
}
END{
print h RS m
}
' infile
使用array
awk '/^@/{
h=$0;min="";
next
}
min==""||$3<min{
min=$3;
l[h]=$0
}
END{
for(i in l)
print i RS l[i]
}
' infile
测试结果:
$ cat infile
@ 62.65 -50.35
0 1.50 1.676
1.67 1.50 1.677
1.67 2.25 1.423
2.90 2.25 2.902
2.90 4.95 2.903
3.04 4.95 3.049
@ 63.61 -50.45
0 1.50 1.654
3.42 1.50 1.875
3.43 2.19 3.430
5.31 2.19 1.032
5.32 6.23 5.320
5.43 6.23 5.434
输出-1(推荐)
$ awk '/^@/{if(h){print h RS m}min=""; h=$0; next}min=="" || $3 < min{min=$3; m=$0}END{print h RS m}' infile
@ 62.65 -50.35
1.67 2.25 1.423
@ 63.61 -50.45
5.31 2.19 1.032
输出-2
$ awk '/^@/{h=$0;min="";next}min==""||$3<min{min=$3;l[h]=$0}END{for(i in l)print i RS l[i]}' infile
@ 62.65 -50.35
1.67 2.25 1.423
@ 63.61 -50.45
5.31 2.19 1.032
答案 1 :(得分:1)
根据以下脚本,Awk可以很容易地做到这一点:
awk '
$1=="@" { first=1; key=$0; next }
first==1 { lowest=$3; line[key]=$0; first=0; next }
{ if ($3 < lowest) { lowest=$3; line[key]=$0 } }
END { for (key in line) { printf "%s\n%s\n", key, line[key] } }
' <<EOF
@ 62.65 -50.35
0 1.50 1.676
1.67 1.50 1.677
1.67 2.25 1.423
2.90 2.25 2.902
2.90 4.95 2.903
3.04 4.95 3.049
@ 63.61 -50.45
0 1.50 1.654
3.42 1.50 1.875
3.43 2.19 3.430
5.31 2.19 1.032
5.32 6.23 5.320
5.43 6.23 5.434
EOF
根据要求,输出为:
@ 62.65 -50.35
1.67 2.25 1.423
@ 63.61 -50.45
5.31 2.19 1.032
打破代码澄清:
$1=="@" { # For all header lines:
first=1 # Flag that you're starting a new block.
key=$0 # Save the key.
next # Go back for next line.
}
first==1 { # For first line in each block:
lowest=$3 # It must be lowest.
line[key]=$0 # Store line.
first=0 # Now processing subsequent lines in block.
next # Go back for next line.
}
{ # For non-first-lines-in-block:
if ($3 < lowest) { # Only if this one is lower.
lowest=$3 # Store value and line.
line[key]=$0
}
}
END { # At end, simply output associative array.
for (key in line) {
printf "%s\n%s\n", key, line[key]
}
}
请记住,假设标题行是唯一的。如果可能存在重复项并且您希望对其进行明确处理,则可以通过NR
和$0
的组合创建密钥。
答案 2 :(得分:1)
这是一种完全不同的awk方法。
awk 'BEGIN {RS="@"} {s=$3 OFS $4 OFS $5; n=$5; for (i=5;i<=NF;i+=3) {if ($i<n) {s=$(i-2) OFS $(i-1) OFS $i; n=$5} }} n { print "@ " $1 OFS $2 ORS s }' infile
或者分发以便于评论:
BEGIN {
RS="@" # "@" as our record separator
}
{
s=$3 OFS $4 OFS $5 # store the first line...
n=$5
for (i=5;i<=NF;i+=3) { # for each 3rd field on a line,
if ($i<n) { # test its value and
s=$(i-2) OFS $(i-1) OFS $i # store a new value if the
n=$5 # condition matches
}
}
}
n {
print "@ " $1 OFS $2 ORS s # print records once we have them.
}
答案 3 :(得分:0)
以下是使用awk命令的另一种解决方案。
awk '
/^@/{if(b)print a;print $0;next}
!b||$3<b{b=$3;a=$0}
END{print a}
' infile
/^@/{if(b)print a;print $0;next}
表示以@
开头的行如果定义了b,则打印a(在第一行a和b未定义)
打印该行并转到下一行
!b||$3<b{b=$3;a=$0}
表示每行不包含以@
开头的行如果未定义b或$ 3小于b,则保留3美元b并保持行
END{print a}
最后,我们必须打印存储在
中的行