我想从多个文件中提取 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 ......)都有两个部分(第1部分,第2部分)。每个文件具有相同的行数。 内容如下:
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 _part 1 ,问题 1 _part 2 ,问题 2 _part 1 ,问题 2 _part 2 ,问题 3 _part 1 ,问题 3 _part的 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 )时,这是一种疯狂的方法。 有人能帮我解决一些能够处理多个文件的简单解决方案吗? 谢谢!
答案 0 :(得分:7)
以下是使用awk
和一系列文件的一种方式:
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 : "")
是一个三元操作,设置为将数组值构建为记录。它只是询问文件行号是否已经在数组中。如果是这样,请在添加第五列之前添加数组值,然后添加默认文件分隔符。否则,如果行号不在数组中,请不要添加任何内容,只需将其等于第五列。
在剧本结束时:
答案 1 :(得分:1)
试试这个。我的脚本假设每个文件都有相同的行数。
# 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个文件,在AMD Athlon(tm)X2双核处理器BE-2400上,每7行长 2分57.865秒。
PS:我的脚本的时间与行数呈线性增长。合并1000行的文件需要很长时间。您应该考虑学习awk并使用史蒂夫的脚本。我对它进行了测试:对于4800个文件,每个文件有1000行,只需 65秒!
答案 2 :(得分:1)
仅适用于~4000个文件,您应该可以:
find . -name sample_problem*_part*.txt | xargs paste
如果find
以错误的顺序命名,请将其输入sort
:
find . -name sample_problem*_part*.txt | sort ... | xargs paste
答案 3 :(得分:1)
# 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
假设第一个和第二个文件的行数少于第三个文件(缺少的值被'?'
替换)。
答案 4 :(得分:0)
您可以将awk输出传递给粘贴并将其重定向到新文件,如下所示:
粘贴&lt;(awk&#39; {print $ 3}&#39; file1)&lt;(awk&#39; {print $ 3}&#39; file2)&lt;(awk&#39; {print $ 3}&#39; file3)&gt; file.txt