输入文件包含多行,如
0 1 0 0 0 1 1 0 0 0 / 1 0 / 1 0 / 1
0 1 0 1 0 0 0 0 -1 3 / 4 1 / 4 1 / 2
我想复制输入中的每一行,在原始行下面插入3个副本,并在结尾处修改分数。我希望输出是
0 1 0 0 0 1 1 0 0 0 / 1 0 / 1 0 / 1
0 1 0 0 0 1 1 0 0 0 / 1 1 / 2 1 / 2
0 1 0 0 0 1 1 0 0 1 / 2 0 / 1 1 / 2
0 1 0 0 0 1 1 0 0 1 / 2 1 / 2 0 / 1
0 1 0 1 0 0 0 0 -1 3 / 4 1 / 4 1 / 2
0 1 0 1 0 0 0 0 -1 3 / 4 3 / 4 0 / 1
0 1 0 1 0 0 0 0 -1 1 / 4 1 / 4 0 / 1
0 1 0 1 0 0 0 0 -1 1 / 4 3 / 4 1 / 2
对分数的修改遵循模式
(0,0,0) <- original fractions
(0,+1/2,+1/2)
(+1/2,0,+1/2)
(+1/2,+1/2,0)
但是,如果分数大于1
i.e. 3/4 + 1/2 = 5/4
它必须从中扣除1
so 5/4 -> 1/4
想将此解决方案添加到我拥有的当前bash脚本中。我作为我的&#34;输入&#34;是迄今为止我的脚本的结果。也许是一个awk或sed命令来实现预期的结果?
答案 0 :(得分:1)
awk
救援!
$ awk 'BEGIN{FS=OFS="\t"}
function addHalf(v) {split(v,a," / "); # split num/denom
n=2*a[1]+a[2]; d=2*a[2]; # add 1/2
if(n>=d) n-=d; # modulus 1
while(!(n%2 || d%2)) {n/=2;d/=2} # normalize if both even
return n " / " d}
{print;
for(i=2;i>=0;i--) # iterate over last three fields
{j=NF-(i+1)%3; k=NF-(i+2)%3; # compute indices
tj=$j; tk=$k; # save values
$j=addHalf(tj); $k=addHalf(tk); # modify selected indices
print; # print modified line
$j=tj; $k=tk}}' file # revert to saved values
答案 1 :(得分:1)
这将使您获得使用GNU awk为真正的多维数组,gensub()和\ s / \ S简写来识别原始分数和应用于每个分数的增量:
$ cat tst.awk
BEGIN {
split("\
(0,0,0) \
(0,+1/2,+1/2) \
(+1/2,0,+1/2) \
(+1/2,+1/2,0) \
",modRows,/[[:space:])(]+/)
for (i=1; i in modRows; i++) {
row = modRows[i]
if ( row ~ /\S/ ) {
deltas[++numRows][1]
numCols = split(row,deltas[numRows],/,/)
}
}
}
{
head = gensub(/^((\s*\S+){9})(.*)/,"\\1",1)
tail = gensub(/^(\s*(\S+\s+){9})(.*)/,"\\3",1)
tail = gensub(/ ([^0-9]) /,"\\1","g",tail)
split(tail,fracts)
for (rowNr=1; rowNr <= numRows; rowNr++) {
printf "%s", head
for (colNr=1; colNr <= numCols; colNr++) {
fract = fracts[colNr]
delta = deltas[rowNr][colNr]
printf "%s%s", OFS, addDelta(fract,delta)
}
print ""
}
}
function addDelta(oldFract,delta, newFract) {
newFract = "(" oldFract " + " delta ")" # <-- do the math here!
return newFract
}
$ gawk -f tst.awk file
0 1 0 0 0 1 1 0 0 (0/1 + 0) (0/1 + 0) (0/1 + 0)
0 1 0 0 0 1 1 0 0 (0/1 + 0) (0/1 + +1/2) (0/1 + +1/2)
0 1 0 0 0 1 1 0 0 (0/1 + +1/2) (0/1 + 0) (0/1 + +1/2)
0 1 0 0 0 1 1 0 0 (0/1 + +1/2) (0/1 + +1/2) (0/1 + 0)
0 1 0 1 0 0 0 0 -1 (3/4 + 0) (1/4 + 0) (1/2 + 0)
0 1 0 1 0 0 0 0 -1 (3/4 + 0) (1/4 + +1/2) (1/2 + +1/2)
0 1 0 1 0 0 0 0 -1 (3/4 + +1/2) (1/4 + 0) (1/2 + +1/2)
0 1 0 1 0 0 0 0 -1 (3/4 + +1/2) (1/4 + +1/2) (1/2 + 0)
所以你需要做的就是在脚本底部的addDeltas()函数中添加你想要计算的每个分数的数学。
答案 2 :(得分:0)
以下Perl脚本按照您要求的方式处理分数。它使用Number::Fraction来进行数学运算。
#!/usr/bin/perl
use strict;
use warnings;
use Number::Fraction;
while (<>) {
print;
my @cols = split /(\s+)/;
for my $modify ([0, 1, 1], [1, 0, 1], [1, 1, 0]) {
my @fractions = map 'Number::Fraction'->new(@cols[@$_]),
[-18, -14],[-12, -8], [-6, -2];
my @newcols;
for my $i (0 .. 2) {
if ($modify->[$i]) {
$fractions[$i] += 'Number::Fraction'->new(1, 2);
$fractions[$i] -= 1 if $fractions[$i] >= 1;
}
push @newcols, $fractions[$i];
}
s{/}{ / }, s{^0$}{0 / 1} for @newcols; # Format the fractions.
print @cols[0..19], $newcols[0],
$cols[25], $newcols[1],
$cols[31], $newcols[2],
"\n";
}
}