2014-11-24 86 views
0

我有多个文件夹Case-1,Case-2 .... Case-N 他们有一个名为PPD的文件,我想提取所有第二列,并把他们成为一个名为123.dat的文件。 看来我不能在for循环中使用awk。awk将同一列的不同文件放入同一个新文件

case=$1 
for ((i = 1; i <= $case ; i ++)) 
do 
    file=Case-$i 
    cp $file/PPD temp$i.dat 

    awk 'FNR==1{f++}{a[f,FNR]=$2} 
     END 
     {for(x=1;x<=FNR;x++) 
      {for(y=1;y<ARGC;y++) 
      printf("%s ",a[y,x]);print ""} }' 

    temp$i.dat >> 123.dat 
done 

现在123.dat只有最后PPD的日期案例-N

我知道我可以使用连接(我以前使用的命令),如果每一个PPD文件至少有一列但是如果我有很多Case文件夹,结果会非常缓慢

回答

2

外部shell脚本和内部awk调用之间的交互不像您期望的那样工作。

每次通过循环,shell脚本都会调用awk一个新的时间,这意味着f将被取消设置,然后第一个子句将它设置为1。它永远不会变成2。也就是说,您将通过外循环为每次迭代开始一个新的awk进程,并且awk每次都从头开始。

还有其他的方法来构建你的代码,但作为最低限度的调整,可以使用-v选项,例如在数$i传递给awk调用awk -v i="$i" ...

请注意,有更好的方法来构建您的整体解决方案,正如其他答复者已经提出的那样;我的意思是这个回答是回答这个问题,“为什么这不工作?”而不是“请重写此代码”。

+1

嗨,danfuzz,你能更准确地解释一下吗?我是新来的,我每天只用Fortran。谢谢 – user3065582 2014-11-24 19:50:20

+0

扩大我的答案一点。 – danfuzz 2014-11-24 19:58:03

2

也许

eval paste $(printf ' <(cut -f2 %s)' Case-*/PPD) 

有可能是多少进程替换就可以一气呵成执行的限制。我做了20列,这很好。进程替换是一个Bash特性,所以一般不能移植到其他Bourne兼容shell。

通配符将按字母顺序展开。如果你想要的数字顺序的情况下,也许使用case-[1-9] case-[1-9][0-9] case-[1-9][0-9][0-9]强制扩展先获得单个数字,然后双位数等。

+0

ksh93 +现在支持进程替换很长时间了,否则就是好东西! ;-) – shellter 2014-11-24 17:26:39

+0

这就是为什么我谨慎地把“一般”。感谢您的评论。 – tripleee 2014-11-24 17:27:38

+0

1+,非常好的使用'eval'和'进程替换' – 2014-11-25 12:31:21

2

以下AWK程序可以帮助你。

#!/usr/bin/awk -f 

BEGIN { 
    # Defaults 
    nrecord=1 
    nfiles=0 
} 

BEGINFILE { 
    # Check if the input file is accessible, 
    # if not skip the file and print error. 
    if (ERRNO != "") { 
     print("Error: ",FILENAME, ERRNO) 
     nextfile 
    } 
} 

{ 
    # Check if the file is accessed for the first time 
    # if so then increment nfiles. This is to keep count of 
    # number of files processed. 
    if (FNR == 1) { 
     nfiles++ 
    } else if (FNR > nrecord) { 
     # Fetching the maximum size of the record processed so far. 
     nrecord=FNR 
    } 

    # Fetch the second column from the file. 
    array[nfiles,FNR]=$2 

} 

END { 
    # Iterate through the array and print the records. 
    for (i=1; i<=nrecord; i++) { 
     for (j=1; j<=nfiles; j++) { 
      printf("%5s", array[j,i]) 
     } 
     print "" 
    } 
} 

输出:

$ ./get.awk Case-*/PPD 
    1 11 21 
    2 12 22 
    3 13 23 
    4 14 24 
    5 15 25 
    6 16 26 
    7 17 27 
    8 18 28 
    9 19 29 
    10 20 30 

这里Case*/PPD扩展到Case-1/PPDCase-2/PPDCase-3/PPD等。以下是生成输出的源文件。

$ cat Case-1/PPD 
1 1 1 1 
2 2 2 2 
3 3 3 3 
4 4 4 4 
5 5 5 5 
6 6 6 6 
7 7 7 7 
8 8 8 8 
9 9 9 9 
10 10 10 10 
$ cat Case-2/PPD 
11 11 11 11 
12 12 12 12 
13 13 13 13 
14 14 14 14 
15 15 15 15 
16 16 16 16 
17 17 17 17 
18 18 18 18 
19 19 19 19 
20 20 20 20 
$ cat Case-3/PPD 
21 21 21 21 
22 22 22 22 
23 23 23 23 
24 24 24 24 
25 25 25 25 
26 26 26 26 
27 27 27 27 
28 28 28 28 
29 29 29 29 
30 30 30 30 
+0

这不会产生相邻列,只是不同连续行上不同文件的输出。 – tripleee 2014-11-24 17:10:50

+0

谢谢,但它不能并排放置数据,我的最终目的是获得平均值,所以我最后一步是$ 1 + $ 2 + ...... $ N,所以我需要将它们并排放置。 – user3065582 2014-11-24 17:21:00

+0

@ user3065582我更新了'AWK'程序以满足您的需求。看看是否有帮助.. – 2014-11-25 09:50:35