在循环中使用paste命令

时间:2012-01-23 22:02:31

标签: bash unix awk paste

我正在使用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.

DESIRED (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

谢谢,

4 个答案:

答案 0 :(得分:2)

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 '{}' +

答案 1 :(得分:1)

根据您在上述评论中看到的假设,您不需要粘贴。试试这个

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= "之类的内容来帮助'解释'正在发生的事情。删除那些完全干净的标签分隔数据。如果需要,将'\ t'更改为':'或'|',或者...... shudder','。将*.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个输入文件。

我希望这会有所帮助。

P.S。欢迎使用StackOverflow(SO)请记住阅读常见问题解答,http://tinyurl.com/2vycnvr,使用灰色三角形http://i.imgur.com/kygEP.png投票选出好的Q / A,并接受解决问题的答案,如果有的话,勾选复选标记http://i.imgur.com/uqJeW.png

答案 2 :(得分:1)

这个怎么样:

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"; 
}'

我可能会使用更通用的脚本作为主脚本,如果需要,我会创建一个'one-liner',用当前感兴趣的特定参数集调用主脚本。

另一个可能是障碍的关键点:paste不仅限于2个文件;它可以粘贴尽可能多的文件,你可以打开(给予或约3)。

答案 3 :(得分:0)

这可能对您有用:

echo *.dat | sed 's/\S*/<(cut -f2 &)/2g;s/^/paste /' | bash >all.dat