我正在使用 Fedora 和 bash 对我拥有的文件进行一些文本操作。我正在尝试合并大量文件,每个文件都有两列数据。我想从这些文件中提取文件第二列的数据,并将其放入一个文件中。以前,我使用了以下脚本:
paste 0_0.dat 0_6.dat 0_12.dat | awk '{print $1, $2, $4}' >0.dat
但是随着文件数量的增加,这变得非常困难——尝试处理 100 个文件。于是我就上网查了一下有没有一种简单的方法可以实现这一点,但是却空手而归。
如果可能的话,我想调用“for”循环——例如,
for i in $(seq 0 6 600)
do
paste 0_0.dat | awk '{print $2}'>>0.dat
done
但这当然不适用于粘贴命令。
如果您对如何做我想做的事情有任何建议,请告诉我......
数据文件 #1 如下所示(由空格分隔)
-180 0.00025432
-179 0.000309643
-178 0.000189226
.
.
.
-1 2E-5
0 1.4E-6
1 0.00000
.
.
.
178 0.0023454268
179 0.002352534
180 0.001504992
数据文件#2
-180 0.0002352
-179 0.000423452
-178 0.00019304
.
.
.
-1 2E-5
0 1.4E-6
1 0.00000
.
.
.
178 0.0023454268
179 0.002352534
180 0.001504992
第一列从 -180 到 180,增量为 1。
想要的 (n 是列数;文件数)
-180 0.00025432 0.00025123 0.000235123 0.00023452 0.00023415 ... n
-179 0.000223432 0.0420504 0.2143450 0.002345123 0.00125235 ... n
.
.
.
-1 2E-5
0 1.4E-6
1 0.00000
.
.
.
179 0.002352534 ... n
180 0.001504992 ... n
谢谢,
join
可以得到你想要的结果。
join <(sort -r file1) <(sort -r file2)
[jaypal:~/Temp] cat file1
-180 0.00025432
-179 0.000309643
-178 0.000189226
[jaypal:~/Temp] cat file2
-180 0.0005524243
-179 0.0002424433
-178 0.0001833333
[jaypal:~/Temp] join <(sort -r file1) <(sort -r file2)
-180 0.00025432 0.0005524243
-179 0.000309643 0.0002424433
-178 0.000189226 0.0001833333
要一次处理多个文件,您可以使用
find
命令 -
find . -type f -name "file*" -exec join '{}' +
这个怎么样:
paste "$@" | awk '{ printf("%s", $1);
for (i = 2; i < NF; i += 2)
printf(" %s", $i); printf "\n";
}'
这假设您没有遇到
paste
的限制(检查它可以有多少个打开的文件)。 "$@"
表示法的意思是“给出的所有参数,与给定的完全相同”。 awk
脚本只是从粘贴输出的每一行打印 $1
,后跟偶数列;随后是换行符。它不验证奇数列是否全部匹配;这样做也许是明智的,您可以在 awk
中编写一个大致相似的循环来执行此操作。它也不检查该行的字段数是否与上一行的字段数相同;这是另一个合理的检查。但这确实可以一次完成所有文件的全部工作 - 对于基本上任意的文件列表。
我有 100 个输入文件 - 如何使用此代码打开这些文件?
你把我原来的答案放在脚本“filter-data”中;您使用
seq
生成的 101 个文件名调用脚本。 paste
命令将所有101个文件粘贴在一起; awk
命令选择您感兴趣的列。
filter-data $(seq --format="0_%g.dat" 0 6 600)
使用以下格式的
seq
命令将列出 101 个文件名;这些是将要粘贴的 101 个文件。
您甚至可以不使用
filter-data
脚本:
paste $(seq --format="0_%g.dat" 0 6 600) | awk '{ printf("%s", $1);
for (i = 2; i < NF; i += 2)
printf(" %s", $i); printf "\n";
}'
我可能会使用更通用的脚本作为主脚本,如果需要,我会创建一个“单行”,用当前感兴趣的一组特定参数调用主脚本。
另一个可能成为绊脚石的关键点:
paste
不限于2个文件;它可以粘贴尽可能多的文件(大约 3 个)。
根据我在上面评论中看到的假设,您不需要粘贴。试试这个
awk '{
arr[$1] = arr[$1] "\t" $2 };
END {for (x=-180;x<=180;x++) print x "\t" arr[x]
}' *.txt \
| sort -n
请注意,我们只是根据第一个字段中的值将所有值放入数组中,并根据 $1 键附加值。读入所有数据后,END 部分打印出键和值。我添加了诸如
"x="
、":vals= "
之类的内容来帮助“解释”正在发生的事情。删除这些以获得完全干净的制表符分隔数据。如果需要的话,将“ ”更改为“:”或“ |”,或者...颤抖“,”。将 *.txt
更改为您的每个文件规范。
请注意,所有 Unix 命令行对 1 次调用中可以处理的文件名的数量和大小(文件名的长度,而不是内部数据)都有限制。如果您收到有关此问题的错误消息,请告诉我们。
要排序的管道确保数据按第 1 列排序。
根据我的测试数据,输出是
-178 0.0001892261 0.0001892262 0.0001892263 0.000189226
-179 0.0003096431 0.0003096432 0.0003096433 0.000309643
-180 0.000254321 0.000254322 0.000254323 0.00025432
178 0.0001892261 0.0001892262 0.0001892263 0.000189226
179 0.0003096431 0.0003096432 0.0003096433 0.000309643
180 0.000254321 0.000254322 0.000254323 0.00025432
基于 4 个输入文件。
这可能对你有用:
echo *.dat | sed 's/\S*/<(cut -f2 &)/2g;s/^/paste /' | bash >all.dat