我的文件看起来像
file0 file1 file2
a 1 ##
a 1 ##
b 2 @@
b 2 @@
我想逐行合并这些文件,所以看起来应该是
merged file
a
a
1
1
##
##
b
b
2
2
@@
@@
我的意思是,为每个文件选择一些行并将它们合并到一个文件中。 我试过下面的bash脚本。
touch ini.dat
n=2
linenum=$(wc -l < file0)
iter=$((linenum/n))
for i in $(seq 0 1 $iter)
do
for j in $(seq 0 1 2)
do
awk 'NR > '$(($i*$n))' && NR <= '$((($i+1)*$n))'' file"$j" > tmp
cat ini.dat tmp > tmpp
cp tmpp ini.dat
rm tmpp
done
done
它工作正常,但需要太多时间。有没有有效的方法?
答案 0 :(得分:0)
这个awk
应该可以胜任你的shell脚本:
awk 'fn != FILENAME {
fn = FILENAME
n = 1
}
NF {
a[FILENAME,n++] = $0
}
END {
for(i=0; i<(n-1)/2; i++) {
for(j=1; j<ARGC; j++)
printf "%s\n%s\n", a[ARGV[j],i*2+1], a[ARGV[j],i*2+2];
print ""
}
}' file{0..2}
a
a
1
1
##
##
b
b
2
2
@@
@@
单行:
awk 'fn != FILENAME{fn=FILENAME; n=1} NF{a[FILENAME,n++]=$0} END{for(i=0; i<(n-1)/2; i++) { for(j=1; j<ARGC; j++) printf "%s\n%s\n", a[ARGV[j],i*2+1], a[ARGV[j],i*2+2]; print "" } }' file{0..2}
答案 1 :(得分:0)
这是另一个awk
,而不是缓存所有内容
paste file{0..2} | awk -v n=2 '
function pr() {for(j=1;j<=NF;j++)
for(i=0;i<n;i++) print a[i,j]}
{for(j=1;j<=NF;j++) a[c+0,j]=$j; c++}
!(NR%n) {pr(); delete a; c=0}
END {pr()}'
如果行数不能被n整除,则会填充空行。
答案 2 :(得分:0)
你的脚本有两个缺陷导致它变慢:
创建并复制了很多文件。特别是... > tmp; cat ini.dat tmp > tmpp; cp tmpp ini.dat
可以写成... >> ini.dat
。
要读取文件的 i 行,脚本必须从头开始扫描该文件,直到到达 i 行。如果重复完成 i = 1,2,3,..., n ,则需要 O ( n 2 )。将整个文件( O ( n ))读入数组并通过索引( O (1))访问行只需要< EM> 0 的(名词的)。
以下bash脚本可以更快地完成工作。 linesPerBlock
对应于脚本中的参数n
。脚本将打印尽可能多的块。那就是:
#! /bin/bash
files=(file{0..2})
linesPerBlock=2
starts=(0)
maxLines=9223372036854775807 # bash's max. number
for i in "${!files[@]}"; do
lineCount="$(wc -l < "${files[i]}")"
(( lineCount < maxLines )) && (( maxLines = lineCount ))
(( starts[i+1] = starts[i] + maxLines ))
mapfile -t -O "${starts[i]}" -n "$maxLines" lines < "${files[i]}"
done
for (( b = 0; b < maxLines / linesPerBlock; ++b )); do
for f in "${!files[@]}"; do
start="${starts[f]}"
for (( i = 0; i < linesPerBlock; ++i )); do
echo "${lines[start + b*linesPerBlock + i]}"
done
done
done > outputFile