我想从多个文件中提取第5列(以数字顺序命名),并将这些列按顺序粘贴到一个输出文件中。
文件名称如下所示:
sample_problem1_part1.txt sample_problem1_part2.txt sample_problem2_part1.txt sample_problem2_part2.txt sample_problem3_part1.txt sample_problem3_part2.txt ......
每个问题文件(1,2,3 …)有两个部分(part1,part2)。 每个文件具有相同的行数。 内容如下所示:
sample_problem1_part1.txt 1 1 20 20 1 1 7 21 21 2 3 1 22 22 3 1 5 23 23 4 6 1 24 24 5 2 9 25 25 6 1 0 26 26 7 sample_problem1_part2.txt 1 1 88 88 8 1 1 89 89 9 2 1 90 90 10 1 3 91 91 11 1 1 92 92 12 7 1 93 93 13 1 5 94 94 14 sample_problem2_part1.txt 1 4 330 30 a 3 4 331 31 b 1 4 332 32 c 2 4 333 33 d 1 4 334 34 e 1 4 335 35 f 9 4 336 36 g
输出应该如下所示:(在问题1_部分1 , 问题1_部分2 , 问题2_部分1 , 问题2_部分2 , 问题3_部分1 , 问题3_部分2等等的序列中 )
1 8 a ... 2 9 b ... 3 10 c ... 4 11 d ... 5 12 e ... 6 13 f ... 7 14 g ...
我正在使用:
paste sample_problem1_part1.txt sample_problem1_part2.txt > \ sample_problem1_partall.txt paste sample_problem2_part1.txt sample_problem2_part2.txt > \ sample_problem2_partall.txt paste sample_problem3_part1.txt sample_problem3_part2.txt > \ sample_problem3_partall.txt
接着:
for i in `find . -name "sample_problem*_partall.txt"` do l=`echo $i | sed 's/sample/extracted_col_/'` `awk '{print $5, $10}' $i > $l` done
和:
paste extracted_col_problem1_partall.txt \ extracted_col_problem2_partall.txt \ extracted_col_problem3_partall.txt > \ extracted_col_problemall_partall.txt
它可以很好地处理几个文件,但是当文件数量很大(超过4000 )时,这是一个疯狂的方法。 任何人都可以帮助我更简单的解决scheme,能够处理多个文件,请? 谢谢!
下面是使用awk
和排序的文件glob的一种方法:
awk '{ a[FNR] = (a[FNR] ? a[FNR] FS : "") $5 } END { for(i=1;i<=FNR;i++) print a[i] }' $(ls -1v *)
结果:
1 8 a 2 9 b 3 10 c 4 11 d 5 12 e 6 13 f 7 14 g
说明:
对于每个输入文件的每一行输入:
将文件行号添加到值为列5的数组中。
(a[FNR] ? a[FNR] FS : "")
是一个三元操作,它被设置为建立数组值作为记录。 它只是询问文件行号是否已经在数组中。 如果是这样,请在添加第五列之前添加数组值,然后添加默认文件分隔符。 否则,如果行号不在数组中,则不要预先计算任何值,只要让它等于第五列即可。
在脚本的最后:
对于只有〜4000个文件,你应该可以这样做:
find . -name sample_problem*_part*.txt | xargs paste
如果find
以错误的顺序给出名字,管它sort
:
find . -name sample_problem*_part*.txt | sort ... | xargs paste
# print filenames in sorted order find -name sample\*.txt | sort | # extract 5-th column from each file and print it on a single line xargs -n1 -I{} sh -c '{ cut -s -d " " -f 5 $0 | tr "\n" " "; echo; }' {} | # transpose python transpose.py ?
其中transpose.py
:
#!/usr/bin/env python """Write lines from stdin as columns to stdout.""" import sys from itertools import izip_longest missing_value = sys.argv[1] if len(sys.argv) > 1 else '-' for row in izip_longest(*[column.split() for column in sys.stdin], fillvalue=missing_value): print " ".join(row)
1 8 a 2 9 b 3 10 c 4 11 d 5 ? e 6 ? f ? ? g
假设第一个和第二个文件比第三个文件有更少的行(缺少的值被替换为'?'
)。
试试这个。 我的脚本假定每个文件都有相同的行数。
# get number of lines lines=$(wc -l sample_problem1_part1.txt | cut -d' ' -f1) for ((i=1; i<=$lines; i++)); do for file in sample_problem*; do # get line number $i and delete everything except the last column # and then print it # echo -n means that no newline is appended echo -n $(sed -n ${i}'s%.*\ %%p' $file)" " done echo done
这工作。 对于4800个文件,每7条线需要2分57.865秒的AMD Athlon(TM)X2双核处理器BE-2400。
PS:我的脚本的时间与线的数量成线性增长。 合并1000行文件需要很长时间。 你应该考虑学习awk,并使用史蒂夫的脚本。 我测试了它:对于4800个文件,每个1000行只花了65秒!
您可以通过awk输出粘贴并将其重定向到一个新文件,如下所示:
粘贴<(awk'{print $ 3}'file1)<(awk'{print $ 3}'file2)<(awk'{print $ 3}'file3)> file.txt