循环使用粘贴命令

问题描述 投票:0回答:4

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

谢谢,

bash unix awk paste
4个回答
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
投票

这个怎么样:

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 个)。


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= "
之类的内容来帮助“解释”正在发生的事情。删除这些以获得完全干净的制表符分隔数据。如果需要的话,将“ ”更改为“:”或“ |”,或者...颤抖“,”。将
*.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 个输入文件。


0
投票

这可能对你有用:

echo *.dat | sed 's/\S*/<(cut -f2 &)/2g;s/^/paste /' | bash >all.dat
© www.soinside.com 2019 - 2024. All rights reserved.