考虑以下(排序的(文件test.txt
,其中第一列中a
出现3次,b
出现一次,c
出现2次,而d
出现4次。
a 1
a 2
a 1
b 1
c 1
c 1
d 2
d 1
d 2
d 1
我想将此文件拆分为最多4行的较小文件。但是,我需要将组保留在较小的文件中,这意味着列$1中以相同值开头的所有行都需要在同一个文件中。在这个例子中,组的大小永远不会大于期望的输出长度。
预期输出为:
文件1:
a 1
a 2
a 1
b 1
文件2:
c 1
c 1
文件3:
d 2
d 1
d 2
d 1
从预期的输出中,您可以看到,如果两个或多个组加在一起的行数小于最大行数(此处为4(,则它们应该进入同一个文件。
因此:a
+b
总共有4个条目,它们可以进入同一个文件。然而,c+d总共有6个entri。因此,c必须进入自己的文件。
我知道这个Awk oneliner:
awk '{print>$1".test"}' test.txt
但这会为每个组生成一个单独的文件。这在我面临的现实世界问题中没有多大意义,因为这会导致大量文件被传输到HPC并返回,从而使开销过大。
首选bash解决方案。但它也可能是Python。
另一个awk。度过了忙碌的一天,这只是用你的样本数据进行测试,所以任何事情都可能发生。它创建名为filen.txt
的文件,其中n
>0:
$ awk -v n=4 '
BEGIN {
fc=1 # file numbering initialized
}
{
if($1==p||FNR==1) # when $1 remains same
b=b (++cc==1?"":ORS) $0 # keep buffering
else {
if(n-(cc+cp)>=0) { # if room in previous file
print b >> sprintf("file%d.txt",fc) # append to it
cp+=cc
} else { # if it just won t fit
close(sprintf("file%d.txt",fc))
print b > sprintf("file%d.txt",++fc) # creat new
cp=cc
}
b=$0
cc=1
}
p=$1
}
END { # same as the else above
if(n-(cc+cp)>=0)
print b >> sprintf("file%d.txt",fc)
else {
close(sprintf("file%d.txt",fc))
print b > sprintf("file%d.txt",++fc)
}
}' file
我希望我已经正确理解了您的需求,您能在用GNUawk
编写和测试后尝试以下内容吗。
awk -v count="1" '
FNR==NR{
max[$1]++
if(!a[$1]++){
first[++count2]=$1
}
next
}
FNR==1{
for(i in max){
maxtill=(max[i]>maxtill?max[i]:maxtill)
}
prev=$1
}
{
if(!b[$1]++){++count1};
c[$1]++
if(prev!=$1 && prev){
if((maxtill-currentFill)<max[$1]){count++}
else if(maxtill==max[$1]) {count++}
}
else if(prev==$1 && c[$1]==maxtill && count1<count2){
count++
}
else if(c[$1]==maxtill && prev==$1){
if(max[first[count1+1]]>(maxtill-c[$1])){ count++ }
}
prev=$1
outputFile="outfile"count
print > (outputFile)
currentFill=currentFill==maxtill?1:++currentFill
}
' Input_file Input_file
用OP的样本输入文件测试上述解决方案:
cat Input_file
a 1
a 2
a 1
b 1
c 1
c 1
d 2
d 1
d 2
d 1
它将创建3个名为outputfile1、outputfile2和outputfile3的输出文件,如下所示。
cat outfile1
a 1
a 2
a 1
b 1
cat outfile2
c 1
c 1
cat outfile3
d 2
d 1
d 2
d 1
第二次测试(使用我的自定义样本(:使用我自己的样本Input_file,假设下面是Input_file。
cat Input_file
a 1
a 2
a 1
b 1
c 1
c 1
d 2
d 1
d 2
d 1
d 4
d 5
当我运行上述解决方案时,将创建两个名为outputfile1
和outputfile2
的输出文件,如下所示。
cat outputfile1
a 1
a 2
a 1
b 1
c 1
c 1
cat outfile2
d 2
d 1
d 2
d 1
d 4
d 5
这可能适用于您(GNU sed、bash和csplit(:
f(){
local g=$1
shift
while (( $#>1))
do
(($#==2)) && echo $2 && break
(($2-$1==$g)) && echo $2 && shift && continue
(($3-$1==$g)) && echo $3 && shift 2 && continue
(($2-$1<$g)) && (($3-$1>$g)) && echo $2 && shift && continue
set -- $1 ${@:3}
done
}
csplit file $(f 4 $(sed -nE '1=;N;/^(S+s).*n1/!=;D' file))
这将把file
拆分为名为xxnn
的单独文件,其中nn
为00、01、02,。。。
sed命令生成一个行号列表,在更改键时拆分文件。
然后,函数CCD_ 16重写将它们分组为4或更小长度的这些数字。
~