根据bash中第一列中的组数和最大行数拆分文件



考虑以下(排序的(文件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

当我运行上述解决方案时,将创建两个名为outputfile1outputfile2的输出文件,如下所示。

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或更小长度的这些数字。

~

相关内容

  • 没有找到相关文章

最新更新