我在文件中有这些记录:
1867 121 2 56
1868 121 1 6
1868 121 2 65
1868 122 0 53
1869 121 0 41
1869 121 1 41
1871 121 1 13
1871 121 2 194
我想得到这个输出:
1867 121 2 56
1868 121 1 6
1868 121 2 65
1868 122 0 53
1869 121 0 41
1869 121 1 41
1870 121 0 0
1871 121 1 13
1871 121 2 194
区别在于1870 121 0 0
行。
因此,如果第一列中的数字之间的差异大于1,那么我们必须包含缺少数字的行(上面的情况是1870
)和其他列。一个人应该以某种方式得到其他列,让第二列成为列数的可能值的最小值(在示例中,这些值可能是121
或122
),并且与第三列情况相同。最后一列的值总是为零。
有人可以给我一些建议吗?提前谢谢!
我试图用awk
来解决它,但也许还有其他更好或更实用的解决方案......
答案 0 :(得分:2)
这样的事情可以起作用 -
awk 'BEGIN{getline;a=$1;b=$2;c=$3}
NR==FNR{if (b>$2) b=$2; if (c>$3) c=$3;next}
{if ($1-a>1) {x=($1-a); for (i=1;i<x;i++) {print (a+1)"\t"b,c,"0";a++};a=$1} else a=$1;print}' file file
BEGIN{getline;a=$1;b=$2;c=$3}
-
在此 BEGIN
块中,我们读取了第一行,并将column 1
中的值分配给变量a
,将column 2
分配给变量{{1 }和b
变量column 3
。
c
-
在此我们浏览整个文件(NR==FNR{if (b>$2) b=$2; if (c>$3) c=$3;next}
)并跟踪NR==FNR
和column 2
中可能的最低值,并将其存储在变量column 3
和{分别为{1}}。我们使用b
来避免运行第二个c
语句。
next
-
此pattern{action}
语句检查{if ($1-a>1) {x=($1-a); for (i=1;i<x;i++) {print (a+1)"\t"b,c,"0";a++};a=$1} else a=$1;print}
中的值,并将其与action
进行比较。如果差异大于1,我们会column 1
添加所有缺失的行,并将a
的值设置为for loop
。如果连续行上a
中的值不大于1,我们会将$1
的值分配给column 1
和column 1
。
a
答案 1 :(得分:1)
Perl解决方案。也应该适用于大文件,因为它不会将整个文件加载到内存中,而是遍历文件两次。
#!/usr/bin/perl
use warnings;
use strict;
my $file = shift;
open my $IN, '<', $file or die $!;
my @mins;
while (<$IN>) {
my @cols = split;
for (0, 1) {
$mins[$_] = $cols[$_ + 1] if $cols[$_ + 1] < $mins[$_ ]
or ! defined $mins[$_];
}
}
seek $IN, 0, 0;
my $last;
while (<$IN>) {
my @cols = split;
$last //= $cols[0];
for my $i ($last .. $cols[0]-2) {
print $i + 1, "\t@mins 0\n";
}
print;
$last = $cols[0];
}
答案 2 :(得分:1)
Bash解决方案:
# initialize minimum of 2. and 3. column
read no min2 min3 c4 < "$infile"
# get minimum of 2. and 3. column
while read c1 c2 c3 c4 ; do
[ $c2 -lt $min2 ] && min=$c2
[ $c3 -lt $min3 ] && min=$c3
done < "$infile"
while read c1 c2 c3 c4 ; do
# insert missing line(s) ?
while (( c1- no > 1 )) ; do
((no++))
echo -e "$no $min2 $min3 0"
done
# now insert existing line
echo -e "$c1 $c2 $c3 $c4"
no=$c1
done < "$infile"
答案 3 :(得分:0)
使用awk
的一种方式:
BEGIN {
if ( ARGC > 2 ) {
print "Usage: awk -f script.awk <file-name>"
exit 0
}
## Need to process file twice, duplicate the input filename.
ARGV[2] = ARGV[1]
++ARGC
col2 = -1
col3 = -1
}
## First processing of file. Get min values of second and third columns.
FNR == NR {
col2 = col2 < 0 || col2 > $2 ? $2 : col2
col3 = col3 < 0 || col3 > $3 ? $3 : col3
next
}
## Second processing of file.
FNR < NR {
## Get value of column 1 in first row.
if ( FNR == 1 ) {
col1 = $1
print
next
}
## Compare current value of column 1 with value of previous row.
## Add a new row while difference is bigger than '1'.
while ( $1 - col1 > 1 ) {
++col1
printf "%d\t%d %d %d\n", col1, col2, col3, 0
}
## Assing new value of column 1.
col1 = $1
print
}
运行脚本:
awk -f script.awk infile
结果:
1867 121 2 56
1868 121 1 6
1868 121 2 65
1868 122 0 53
1869 121 0 41
1869 121 1 41
1870 121 0 0
1871 121 1 13
1871 121 2 194