查找特定的列,并用gawk替换具有特定值的以下列
我正在尝试查找我的数据有重复行并删除重复行的所有位置。此外,我正在寻找第二列的值为90,并用指定的特定号码替换下面的第二列。查找特定的列,并用gawk替换具有特定值的以下列
我的数据是这样的:
# Type Response Acc RT Offset
1 70 0 0 0.0000 57850
2 31 0 0 0.0000 59371
3 41 0 0 0.0000 60909
4 70 0 0 0.0000 61478
5 31 0 0 0.0000 62999
6 41 0 0 0.0000 64537
7 41 0 0 0.0000 64537
8 70 0 0 0.0000 65106
9 11 0 0 0.0000 66627
10 21 0 0 0.0000 68165
11 90 0 0 0.0000 68700
12 31 0 0 0.0000 70221
我希望我的数据是这样的:
# Type Response Acc RT Offset
1 70 0 0 0.0000 57850
2 31 0 0 0.0000 59371
3 41 0 0 0.0000 60909
4 70 0 0 0.0000 61478
5 31 0 0 0.0000 62999
6 41 0 0 0.0000 64537
8 70 0 0 0.0000 65106
9 11 0 0 0.0000 66627
10 21 0 0 0.0000 68165
11 90 0 0 0.0000 68700
12 5 0 0 0.0000 70221
我的代码:
BEGIN {
priorline = "";
ERROROFFSET = 50;
ERRORVALUE[10] = 1;
ERRORVALUE[11] = 2;
ERRORVALUE[12] = 3;
ERRORVALUE[30] = 4;
ERRORVALUE[31] = 5;
ERRORVALUE[32] = 6;
ORS = "\n";
}
NR == 1 {
print;
getline;
priorline = $0;
}
NF == 6 {
brandnewline = $0
mytype = $2
$0 = priorline
priorField2 = $2;
if (mytype !~ priorField2) {
print;
priorline = brandnewline;
}
if (priorField2 == "90") {
mytype = ERRORVALUE[mytype];
}
}
END {print brandnewline}
##Here the parameters of the brandnewline is set to the current line and then the
##proirline is set to the line on which we just worked on and the brandnewline is
##set to be the next new line we are working on. (i.e line 1 = brandnewline, now
##we set priorline = brandnewline, thus priorline is line 1 and brandnewline takes
##on line 2) Next, the same parameters were set with column 2, mytype being the
##current column 2 value and priorField2 being the same value as mytype moves to
##the next column 2 value. Finally, we wrote an if statement where, if the value
##in column 2 of the current line !~ (does not equal) value of column two of the
##previous line, then the current line will be print otherwise it will just be
##skipped over. The second if statement recognizes the lines in which the value
##90 appeared and replaces the value in column 2 with a previously defined
##ERRORVALUE set for each specific type (type 10=1, 11=2,12=3, 30=4, 31=5, 32=6).
我已经能够成功地删除然而,重复行,我无法执行我的代码的下一部分,即代替B中指定的值EGIN作为ERRORVALUES(10 = 1,11 = 2,12 = 3,30 = 4,31 = 5,32 = 6)与包含该值的实际列。实质上,我想用我的ERRORVALUE替换该行中的值。
如果有人能帮助我,我会非常感激。
一个挑战是,你不能只比较一行和前一行,因为身份证号码会不同。
awk '
BEGIN {
ERRORVALUE[10] = 1
# ... etc
}
# print the header
NR == 1 {print; next}
NR == 2 || $0 !~ prev_regex {
prev_regex = sprintf("^\\s+\\w+\\s+%s\\s+%s\\s+%s\\s+%s\\s+%s",$2,$3,$4,$5,$6)
if (was90) $2 = ERRORVALUE[$2]
print
was90 = ($2 == 90)
}
'
对于将第2列被改变线路,这破坏了行格式:
# Type Response Acc RT Offset
1 70 0 0 0.0000 57850
2 31 0 0 0.0000 59371
3 41 0 0 0.0000 60909
4 70 0 0 0.0000 61478
5 31 0 0 0.0000 62999
6 41 0 0 0.0000 64537
8 70 0 0 0.0000 65106
9 11 0 0 0.0000 66627
10 21 0 0 0.0000 68165
11 90 0 0 0.0000 68700
12 5 0 0 0.0000 70221
如果这是一个问题,你可以管GAWK的输出为column -t
,或者如果你知道行格式是固定的,在awk程序中使用printf()。
这可能会为你工作:
v=99999
sed ':a;$!N;s/^\(\s*\S*\s*\)\(.*\)\s*\n.*\2/\1\2/;ta;s/^\(\s*\S*\s*\) 90 /\1'"$(printf "%5d" $v)"' /;P;D' file
# Type Response Acc RT Offset
1 70 0 0 0.0000 57850
2 31 0 0 0.0000 59371
3 41 0 0 0.0000 60909
4 70 0 0 0.0000 61478
5 31 0 0 0.0000 62999
6 41 0 0 0.0000 64537
8 70 0 0 0.0000 65106
9 11 0 0 0.0000 66627
10 21 0 0 0.0000 68165
11 99999 0 0 0.0000 68700
12 31 0 0 0.0000 70221
这可能会为你工作:
awk 'BEGIN {
ERROROFFSET = 50;
ERRORVALUE[10] = 1;
ERRORVALUE[11] = 2;
ERRORVALUE[12] = 3;
ERRORVALUE[30] = 4;
ERRORVALUE[31] = 5;
ERRORVALUE[32] = 6;
}
NR == 1 { print ; next }
{ if (a[$2 $6]) { next } else { a[$2 $6]++ }
if ($2 == 90) { print ; n++ ; next }
if (n>0) { $2 = ERRORVALUE[$2] ; n=0 }
printf("% 4i% 8i% 3i% 5i% 9.4f% 6i\n", $1, $2, $3, $4, $5, $6)
}' INPUTFILE
See it in action here at ideone.com。
IMO BEGIN
块很明显。然后会发生以下情况:
- 的
NR == 1
行打印的第一行(并切换到下一行,也该规则只适用于第一行) - ,如果我们已经对任何看到然后检查如果是这样,切换到下一行,否则将其标记为在数组中看到(使用连接的列值作为indecies,,但请注意,如果您的值较大,这可能会失败在第二个和第六个小(例如
2 0020
级联是20020
,它是相同的20 020
),所以你可能想要在索引中添加一个列分隔符,如a[$2 "-" $6]
...并且您可以使用更多的列来更正确地检查) - 如果该行在第二列上有
90
,则打印它,在下一行上交换标志,然后切换到下一行(在输入文件中) - 在下一行检查
ERRORVALUE
中的第二列,如果找到,则替换其内容。 - 然后打印格式化的行。
我同意格伦两次通过文件更好。您可以移除重复的,也许是不连续的,使用哈希像这样的台词:
awk '!a[$2,$3,$4,$5,$6]++' file.txt
根据需要,您应该然后编辑你的价值观。如果您希望在第二列更改值90
到5000
,尝试这样的事情:
awk 'NR == 1 { print; next } { sub(/^90$/, "5000", $2); printf("%4i% 8i% 3i% 5i% 9.4f% 6i\n", $1, $2, $3, $4, $5, $6) }' file.txt
你可以看到,我偷了Zsolt的printf语句(感谢Zsolt的!)的格式,但你可以如有必要编辑此。也可通过管道从第一条语句输出到第二一个不错的一行:
cat file.txt | awk '!a[$2,$3,$4,$5,$6]++' | awk 'NR == 1 { print; next } { sub(/^90$/, "5000", $2); printf("%4i% 8i% 3i% 5i% 9.4f% 6i\n", $1, $2, $3, $4, $5, $6) }'
上述选项的大部分工作,但是这里是我会做的方式,简单而甜美。在回顾其他帖子后,我认为这将是最有效的。另外,这也允许在注释中添加OP的额外请求使90之后的行取代2行之前的变量。这一切都在一次通过。
BEGIN {
PC2=PC6=1337
replacement=5
}
{
if($6 == PC6) next
if(PC2 == 90) $2 = replacement
replacement = PC2
PC2 = $2
PC6 = $6
printf "%4s%8s%3s%5s%9s%6s\n",$1, $2, $3, $4, $5, $6
}
例输入
1 70 0 0 0.0000 57850
2 31 0 0 0.0000 59371
3 41 0 0 0.0000 60909
4 70 0 0 0.0000 61478
5 31 0 0 0.0000 62999
6 41 0 0 0.0000 64537
7 41 0 0 0.0000 64537
8 70 0 0 0.0000 65106
9 11 0 0 0.0000 66627
10 21 0 0 0.0000 68165
11 90 0 0 0.0000 68700
12 31 0 0 0.0000 70221
示例输出
1 70 0 0 0.000000 57850
2 31 0 0 0.000000 59371
3 41 0 0 0.000000 60909
4 70 0 0 0.000000 61478
5 31 0 0 0.000000 62999
6 41 0 0 0.000000 64537
8 70 0 0 0.000000 65106
9 11 0 0 0.000000 66627
10 21 0 0 0.000000 68165
11 90 0 0 0.000000 68700
12 21 0 0 0.000000 70221
首先:非常感谢你的回答就已经非常有帮助。此外,谢谢你这样快速的答复。第二:我有一个担心的是,如果可能的情况是,在我看到$ 2的90美元后,我可以用线替代之前的$ 2两行中的什么?在这个例子中,第11行的$ 2中有90个是可以将第9行中的$ 2更改为BEGIN中描述的格式,如果是的话,我该如何去做这件事? – user1269741 2012-03-14 20:40:49
我可能需要2遍以上的文件:'awk'删除重复的行'| tac | awk'如果之前的值2行是90'|,则替换$ 2 tac' - tac是从最后一行打印文件到第一行的方便工具。否则,awk脚本会变得有点混乱,因为现在必须记住前两行,注意2行之前没有被删除,等等。 – 2012-03-14 20:53:06