假设这是我的档案:
$ cat file.txt
A:1:i
B:2:ii
X:9:iv
使用这样的for循环,我可以单独打印所有字段并重定向到子文件
$ for i in $(seq 1 3); do echo $i; awk -F ":" -v FL=$i '{print $FL}' file.txt > $i.out; done
那样:
$ cat 1.out
A
B
X
$ cat 2.out
1
2
9
$ cat 3.out
i
ii
iv
问题: 我必须在近70列上执行此操作,文件大小接近10 GB。它有效但速度慢。 任何人都可以建议更好/更有效的拆分来处理这个大数据集。谢谢。
$ for i in $(seq 1 70); do echo $i; awk -F ":" -v FL=$i '{print $FL}' *.data > $i.out; done
答案 0 :(得分:6)
考虑到你要做的事情,这应该相当快:
awk -F: '{ for (i=1; i<=NF; i++) print $i > i".out" }' file.txt
答案 1 :(得分:1)
在Perl中你可以这样做:
#!/usr/bin/perl -w
my $n = 3;
my @FILES;
for my $i (1..$n) {
my $f;
open ($f, "> $i.out") or die;
push @FILES, $f;
}
while (<>) {
chomp;
@a = split(/:/);
for my $i (0..$#a) {
print $FILES[$i] $a[$i],"\n";
}
}
close($f) for $f in @FILES;
答案 2 :(得分:1)
Python版
#!/bin/env python
with open('file.txt', 'r') as ih:
while True:
line = ih.readline()
if line == '': break
for i,element in enumerate(line.strip().split(':')):
outfile = "%d.out" % (i+1)
with open(outfile, 'a') as oh:
oh.write("%s\n" % element)
这可能会快一点,因为它只会通过原始文件一次。请注意,可以通过将输出文件保持打开来进一步优化(因为它,我关闭每个文件并为每次写入重新打开它们)。
修改强>
例如:
#!/bin/env python
handles = dict()
with open('file.txt', 'r') as ih:
while True:
line = ih.readline()
if line == '': break
for i,element in enumerate(line.strip().split(':')):
outfile = "%d.out" % (i+1)
if outfile not in handles:
handles[outfile] = open(outfile, 'a');
handles[outfile].write("%s\n" % element)
for k in handles:
handles[k].close()
这使句柄在执行期间保持打开状态,然后在继续/结束之前将它们全部关闭。
答案 3 :(得分:0)
如果您知道有三列,请使用coreutils:
< file.txt tee >(cut -d: -f1 > 1.out) >(cut -d: -f2 > 2.out) >(cut -d: -f3 > 3.out) > /dev/null
为了使它更通用,这是自动生成命令行的一种方法:
# Determine number of fields and generate tee argument
arg=""
i=1
while read; do
arg="$arg >(cut -d: -f$i > $((i++)).out)"
done < <(head -n1 file.txt | tr ':' '\n')
arg
现在是:
>(cut -d: -f1 > 1.out) >(cut -d: -f2 > 2.out) >(cut -d: -f3 > 3.out)
保存到脚本文件:
echo "< file.txt tee $arg > /dev/null" > script
执行:
. ./script
答案 4 :(得分:0)
这是一个使用我不经常看到的功能的bash脚本:要求bash为文件分配文件描述符并将描述符存储在变量中:
# Read the first line to get a count of the columns
IFS=: read -a columns < file.txt
# Open an output file for each column, saving the file descriptor in an array
for c in "${columns[@]}"; do
exec {a}>$((++i)).txt
fds+=( $a )
done
# Iterate through the iput, writing each column to the file opened for it
while IFS=: read -a fields; do
for f in "${fields[@]}"; do
printf "$f\n" >&${fds[++i]}
done
done < file.txt
# Close the file descriptors
for fd in "${fds[@]}"; do
exec {fd}>&-
done