将文本文件中的数据列保存为单独的文件
Save columns of data from a text file as separate files
我正在寻找一种方法来获取包含由制表符分隔的数据列的文本文件:
file.txt
abcd abcd abcd
efgh efgh efgh
ijkl ijkl ijkl
mnop mnop mnop
qrst qrst qrst
我想使用 awk 将每一列数据保存为自己的文本文件,使用数字作为文件名。
但问题是无法预测它们将包含的文本的列数,
我唯一知道的是列将由制表符分隔。
这样
awk '{ print }' file
将打印第一列
和:
awk '{ print }' file
将打印第二列
但是我希望将每一列保存为自己的文件。
列数可以是 100 以内的任何值
你可以这样做:
awk 'NR==FNR{max=NF>max ? NF : max; next}
{for(i=1; i<=max; i++) {
fn=sprintf("%s.col", i)
print $i >> fn
close(fn)
}
}' file file
如果你的列宽是统一的,你可以做一遍:
awk 'FNR==1{max=NF}
{for(i=1; i<=max; i++) {
fn=sprintf("%s.col", i)
print $i >> fn
close(fn)
}
}' file
使用您的示例创建这些文件:
$ head *.col
==> 1.col <==
abcd
efgh
ijkl
mnop
qrst
==> 2.col <==
abcd
efgh
ijkl
mnop
qrst
==> 3.col <==
abcd
efgh
ijkl
mnop
qrst
同时打开所有输出文件
一个GNU awk
想法:
awk '{for (i=1;i<=NF;i++) print $i > i".out"}' file
备注:
- 这将打开并保持打开状态,每个输出文件的文件描述符
- 许多
awk
实现对一次可以打开的文件数量有限制;打开和关闭文件非常耗时,因此从性能角度来看,您需要限制打开和关闭操作的次数
GNU awk
对一次可以打开的文件数量有相当高的限制
- 如果你有
GNU awk
并且你收到一个错误说明打开的文件描述符太多然后让我们知道,我们可以考虑另一个想法(例如:运行 一个单独的 awk
对于每组 N 列;使用 in-memory 解决方案 - 假设整个文件可以放入内存)
- 你提到列由
tab spaces
分隔; (不确定你的意思......列由多个制表符和空格分隔?列由制表符或空格分隔?)此答案使用 awk's
默认字段分隔符 'white space' (多个 spaces/tabs 被视为单个定界符);如果您的字段由制表符分隔,但在字段中包含空格,则将 awk '{for ...
更改为 awk -F'\t' '{for ...
in-memory;一次打开一个输出文件;香草 awk
假设输入文件可以放入内存:
一个适用于所有 awk
口味的想法:
awk '
{ for (i=1;i<=NF;i++)
cols[i]=cols[i] (FNR==1 ? "" : ORS) $i
}
END { for (i=1;i<=NF;i++) {
outfile= i ".out"
print cols[i] > outfile
close(outfile)
}
}
' file
in-memory;一次打开一个输出文件; GNU awk
使用GNU awk
的另一个in-memory解决方案(用于multi-dimensional数组支持):
awk '
{ for(i=1;i<=NF;i++)
cols[i][FNR] = $i
}
END { for (i=1;i<=NF;i++) {
outfile= i ".out"
for (j=1;j<=FNR;j++)
print cols[i][j] > outfile
close(outfile)
}
}
' file
所有这 3 个答案生成:
$ head ?.out
==> 1.out <==
abcd
efgh
ijkl
mnop
qrst
==> 2.out <==
abcd
efgh
ijkl
mnop
qrst
==> 3.out <==
abcd
efgh
ijkl
mnop
qrst
绩效考核
设置:
# create a file with 5000 lines and 500 columns; ~19.5 MBytes
awk '
BEGIN { for (i=1;i<=5000;i++) {
printf "%s", "col_1"
for (j=2;j<=500;j++)
printf "\t%s", "col_" j
print ""
}
}
' > multi_column.txt
250 万 open/close 次操作
运行 500 个输出文件中的每个 open/close 的 2x 个答案中的任何一个,对于 5000 个输入行中的每个,(即 5000 x 500 = 2.5 million
open/close 操作):
- 2 分钟后被杀死,处理了 800 行
- 外推:~12.5 分钟 处理 5000 行
- 时间(显然)会因硬件而异(例如,Ed Morton 报告他的答案在他的笔记本电脑上需要 10 分钟)
同时打开所有 (500) 个输出文件
运行 第一个回答(上):
- 10秒生成500个文件,每个文件5000行
- 即使我们不得不限制自己一次处理 20 列......我们可以对输入文件进行 25 次传递,并且仍然在 < 7 分钟内完成(时间可以进一步减少 运行 一些
awk
并行会议)
in-memory;一次打开一个输出文件;香草 awk
运行第二个答案(上)
- 6秒生成500个文件,每个文件5000行
in-memory;一次打开一个输出文件; GNU awk
运行第三个答案(上):
- 3秒生成500个文件,每个文件5000行
- 之前的 in-memory 答案较慢,因为 'find and append' 将新字段添加到 ever-increasing-in-length 数组条目的末尾 (
cols[i]=cols[i] (FNR==1 ? "" : ORS) $i
)
无论您的输入有多少列,所有 awk 都可移植:
awk -F'\t' '{
for (i=1; i<=NF; i++) {
out = $i ".out"
if ( !seen[out]++ ) {
printf "" > out
}
print $i >> out
close(out)
}
}' file
使用数组避免为每一行重复写入过程
awk '
{
for(i=1; i<=NF; i++){
# saving columns in multi-array
# i = column, NR = line
a[i][NR] = $(i)
}
}
END{
# iterating through array
for (col in a){
joined = ""
# joining lines per column
for (line in a[col]){
joined = joined a[col][line] "\n"
}
gsub(/\n$/,"",joined)
# write all joined lines per column at once to col-file
print joined > col".out"
}
}
' file.txt
我正在寻找一种方法来获取包含由制表符分隔的数据列的文本文件:
file.txt
abcd abcd abcd
efgh efgh efgh
ijkl ijkl ijkl
mnop mnop mnop
qrst qrst qrst
我想使用 awk 将每一列数据保存为自己的文本文件,使用数字作为文件名。
但问题是无法预测它们将包含的文本的列数,
我唯一知道的是列将由制表符分隔。
这样
awk '{ print }' file
将打印第一列
和:
awk '{ print }' file
将打印第二列
但是我希望将每一列保存为自己的文件。
列数可以是 100 以内的任何值
你可以这样做:
awk 'NR==FNR{max=NF>max ? NF : max; next}
{for(i=1; i<=max; i++) {
fn=sprintf("%s.col", i)
print $i >> fn
close(fn)
}
}' file file
如果你的列宽是统一的,你可以做一遍:
awk 'FNR==1{max=NF}
{for(i=1; i<=max; i++) {
fn=sprintf("%s.col", i)
print $i >> fn
close(fn)
}
}' file
使用您的示例创建这些文件:
$ head *.col
==> 1.col <==
abcd
efgh
ijkl
mnop
qrst
==> 2.col <==
abcd
efgh
ijkl
mnop
qrst
==> 3.col <==
abcd
efgh
ijkl
mnop
qrst
同时打开所有输出文件
一个GNU awk
想法:
awk '{for (i=1;i<=NF;i++) print $i > i".out"}' file
备注:
- 这将打开并保持打开状态,每个输出文件的文件描述符
- 许多
awk
实现对一次可以打开的文件数量有限制;打开和关闭文件非常耗时,因此从性能角度来看,您需要限制打开和关闭操作的次数 GNU awk
对一次可以打开的文件数量有相当高的限制- 如果你有
GNU awk
并且你收到一个错误说明打开的文件描述符太多然后让我们知道,我们可以考虑另一个想法(例如:运行 一个单独的awk
对于每组 N 列;使用 in-memory 解决方案 - 假设整个文件可以放入内存) - 你提到列由
tab spaces
分隔; (不确定你的意思......列由多个制表符和空格分隔?列由制表符或空格分隔?)此答案使用awk's
默认字段分隔符 'white space' (多个 spaces/tabs 被视为单个定界符);如果您的字段由制表符分隔,但在字段中包含空格,则将awk '{for ...
更改为awk -F'\t' '{for ...
in-memory;一次打开一个输出文件;香草 awk
假设输入文件可以放入内存:
一个适用于所有 awk
口味的想法:
awk '
{ for (i=1;i<=NF;i++)
cols[i]=cols[i] (FNR==1 ? "" : ORS) $i
}
END { for (i=1;i<=NF;i++) {
outfile= i ".out"
print cols[i] > outfile
close(outfile)
}
}
' file
in-memory;一次打开一个输出文件; GNU awk
使用GNU awk
的另一个in-memory解决方案(用于multi-dimensional数组支持):
awk '
{ for(i=1;i<=NF;i++)
cols[i][FNR] = $i
}
END { for (i=1;i<=NF;i++) {
outfile= i ".out"
for (j=1;j<=FNR;j++)
print cols[i][j] > outfile
close(outfile)
}
}
' file
所有这 3 个答案生成:
$ head ?.out
==> 1.out <==
abcd
efgh
ijkl
mnop
qrst
==> 2.out <==
abcd
efgh
ijkl
mnop
qrst
==> 3.out <==
abcd
efgh
ijkl
mnop
qrst
绩效考核
设置:
# create a file with 5000 lines and 500 columns; ~19.5 MBytes
awk '
BEGIN { for (i=1;i<=5000;i++) {
printf "%s", "col_1"
for (j=2;j<=500;j++)
printf "\t%s", "col_" j
print ""
}
}
' > multi_column.txt
250 万 open/close 次操作
运行 500 个输出文件中的每个 open/close 的 2x 个答案中的任何一个,对于 5000 个输入行中的每个,(即 5000 x 500 = 2.5 million
open/close 操作):
- 2 分钟后被杀死,处理了 800 行
- 外推:~12.5 分钟 处理 5000 行
- 时间(显然)会因硬件而异(例如,Ed Morton 报告他的答案在他的笔记本电脑上需要 10 分钟)
同时打开所有 (500) 个输出文件
运行 第一个回答(上):
- 10秒生成500个文件,每个文件5000行
- 即使我们不得不限制自己一次处理 20 列......我们可以对输入文件进行 25 次传递,并且仍然在 < 7 分钟内完成(时间可以进一步减少 运行 一些
awk
并行会议)
in-memory;一次打开一个输出文件;香草 awk
运行第二个答案(上)
- 6秒生成500个文件,每个文件5000行
in-memory;一次打开一个输出文件; GNU awk
运行第三个答案(上):
- 3秒生成500个文件,每个文件5000行
- 之前的 in-memory 答案较慢,因为 'find and append' 将新字段添加到 ever-increasing-in-length 数组条目的末尾 (
cols[i]=cols[i] (FNR==1 ? "" : ORS) $i
)
无论您的输入有多少列,所有 awk 都可移植:
awk -F'\t' '{
for (i=1; i<=NF; i++) {
out = $i ".out"
if ( !seen[out]++ ) {
printf "" > out
}
print $i >> out
close(out)
}
}' file
使用数组避免为每一行重复写入过程
awk '
{
for(i=1; i<=NF; i++){
# saving columns in multi-array
# i = column, NR = line
a[i][NR] = $(i)
}
}
END{
# iterating through array
for (col in a){
joined = ""
# joining lines per column
for (line in a[col]){
joined = joined a[col][line] "\n"
}
gsub(/\n$/,"",joined)
# write all joined lines per column at once to col-file
print joined > col".out"
}
}
' file.txt