bash脚本-进程替换的变量扩展

bash脚本-进程替换的变量扩展,bash,scripting,process,substitution,Bash,Scripting,Process,Substitution,我试图对多列文件的每一列执行分析,并使用“粘贴”将这些列重新连接在一起。我不知道有多少列,所以我使用“wc-w”和一个循环来定义一个命令数组。然后,每个命令都是一个进程替换。下面的脚本显示了我正在尝试的内容,之后将显示输出。值得注意的是,如果我将命令数组回送到终端,然后用鼠标剪切粘贴,效果很好,因此它必须是变量扩展和进程替换的顺序 简而言之,我需要在shell变量中有一个进程替换。有什么想法吗?提前谢谢 --------------script.sh---------------- $ ./sc

我试图对多列文件的每一列执行分析,并使用“粘贴”将这些列重新连接在一起。我不知道有多少列,所以我使用“wc-w”和一个循环来定义一个命令数组。然后,每个命令都是一个进程替换。下面的脚本显示了我正在尝试的内容,之后将显示输出。值得注意的是,如果我将命令数组回送到终端,然后用鼠标剪切粘贴,效果很好,因此它必须是变量扩展和进程替换的顺序

简而言之,我需要在shell变量中有一个进程替换。有什么想法吗?提前谢谢

--------------script.sh----------------

$ ./scipt.sh 
File contents
A B C
D E F
G H I

First try
A B C   G H I
D E F   D E F
G H I   A B C

Second try
A B C   A B C
D E F   D E F
G H I   G H I

Third try
paste: <(cat: No such file or directory

Fourth try
paste: <(cat: No such file or directory

Show the array
paste <(cat file.txt) <(tac file.txt)
$ paste <(cat file.txt) <(tac file.txt)
A B C   G H I
D E F   D E F
G H I   A B C
$ 
可能有一亿行这样的数据。我需要分离每一列,将每一列分离成(比如)1000个块,然后对块中的每个元素进行平均,然后将平均后的列再次合并在一起。对于下面的示例,如果我对每个3个元素的2个块进行平均(而不是每个元素的100K),那么第6列的输出将是:

0.0165     # =(0.027+0.006)/2 - 1st row from each size-3 block
0.042      # =(0.035+0.049)/2 - 2nd row
0.0515     # =(0.068+0.035)/2 - 3rd row
我已经有了程序来做这个平均(这是“一些复杂的分析”),而且效果很好。因此,我所需要做的就是让脚本分离列,将其输入到一些比较分析中,然后使用
paste
将各种输出重新合并到列中。但是,这些文件是v。很大,我不知道有多少列。如果我知道只有两列,那么
paste将“cmd1”和“cmd2”分别定义为单独的数组

$ cmd1=(cat $f)
$ cmd2=(tac $f)
$ paste <("${cmd1[@]}") <("${cmd2[@]}")
A B C   G H I
D E F   D E F
G H I   A B C
试试这个:

{
  cat -<<EOS
10 7.74336e-08 7.30689e-08 0.359106        19.981796       -0.160611       0.027
10 7.74336e-08 7.30689e-08 0.363938        19.985069       0.041319        0.035
10 7.74336e-08 7.30689e-08 0.363133        19.982094       0.041319        0.068
10 7.74336e-08 7.30689e-08 0.360716        19.981796       -0.160611       0.006
10 7.74336e-08 7.30689e-08 0.361522        19.981796       0.243249        0.049
10 7.74336e-08 7.30689e-08 0.357897        19.986260       0.041319        0.035
EOS
} |
awk '
  BEGIN { binSz=3; binSzLim=binSz ; binSzLim++ }
  NR==1{
    # base error checking on number of cols in first record
    maxCols=NF
    maxColsLim=maxCols ; maxColsLim++
    r=0
  }
  {
    if (NF != maxCols) {
      print "Skipping record, Mismatch in data, expected " maxCols ", found " NF " recs at " NR ":" $0
      next
    }
    r++
    #dbg print "r="r" NR=" NR ":$0=" $0

    # load data into temp arr[] by column
    for (c=1;c<maxColsLim;c++) {
      arr[r,c]+=$c
      #dbg printf ("arr["r","c"]=" arr[r,c] " " )

      avgArr[r,c]++
      #dbg print "avgArr["r","c"]="avgArr[r,c]
    }

    if(r>=binSz) {
      r=0
    }
  }
  END {
    for (r=1;r<binSzLim;r++) {
      #dbg print "r=" r " binSzLim=" binSzLim " " (r<binSzLim) "\t"
      for (c=1;c<maxColsLim;c++) {
        #dbg printf("arr["r","c"]=" arr[r,c] "\tavg=" arr[r,c]/binSz "\t")
        printf(  arr[r,c]/avgArr[r,c] " ")
      }
      printf "\n"
    }
  }
'
我在数据中添加了第一列10,以便于调试sum和avg是否正常工作

这是一个有趣的问题,感谢您的发帖,感谢您继续回答我的问题;-)


{cat-如果您的脚本仍然不起作用,这可能会有额外的帮助。仍然遵循glenn jackman的答案,但另外您可能希望在脚本内部执行此操作

set+o posix

从链接:
“进程替换不是POSIX兼容的功能,因此可能必须通过:set+o POSIX启用它”

您需要使用
tac
,还是只是为了“随机化(ish)”“你的数据?”如果你真的只需要并排获得一堆列,那么粘贴文件有什么问题?
?祝你好运。我只在示例中使用tac。我实际拥有的是类似于:
cols=$(head-n 1$f | wc-w);例如((i=1;iis你有没有理由不使用awk或perl?花一个小时阅读,你会从一个全新的角度看到你的问题。如果你将帖子改为显示简化的示例输入和预期的输出,我们可能会帮助你。那么你已经有了“一些复杂的分析”的代码?祝你好运。我使用awk还不错,更好但是awk在这里对我来说似乎不合适。不幸的是,我不能用语言准确地解释为什么它看起来不合适。我已经更改了上面的帖子作为回复。所以,如果您的输入文件有100Mill行,您的最终输出将是100Mill/1000 over N列?(我今天不太想去,但如果你没有更好的解决方案,我会在有时间的时候尝试awk解决方案).祝您好运,对于好的样本数据,+1!谢谢,但我认为这并不能避免这样一个事实,即在最后一个命令中,我需要为100行以上的行祈祷一定数量的手指!如何在eval前面预挂
time
呢?祝大家好运。谢谢,这似乎起到了作用,与bash一样,我不明白为什么。我本以为“”会取代$cmd[*]作为一个词;但显然不是。
eval
似乎很关键。@hide我不太担心时间-这样每个复杂的分析都在自己的CPU内核上运行。有了awk,我认为它将在一个内核上运行…对吗?但我为您计时,在Intel I7 x4 HT上,6列数据花了4分钟es实时。感谢两位的帮助。我稍后将发布结论性回复并关闭线程。@fergalish,问题在于字符串中的shell语法。
现在我终于理解了
man bash
中的
eval
部分,也就是说,它所做的只是连接和扩展参数。再次感谢。我今天晚些时候会继续讨论。干杯。#Sheller好的,我做了一个简短的分析。令人惊讶的是,awk程序使用的CPU时间更少。但是,原来的程序可以在并行CPU内核上运行,使用的实时性更低。这里:
$time cat file | avg.awk>file.mean real 15m48.754s;user 16m30.090s;sys 0m13.100s$time../mean.sh file>file.mean real 3m12.871s;user 20m27.940s;sys 1m3.130s$
然而,在binSz=1M时,
awk
的估计时间为1½小时,而最初的实时时间仅为4分钟。下一个问题:如何将相同的
stdin
传输到各种流程替换中!请注意此空间:-)再次感谢。@fergalish:非常有趣。谢谢分享。你有,或者你能安装GNU并行吗?这可能会给你所需要的提升。祝你好运。我已经安装了GNU并行,现在使用它还有很多其他原因:-)感谢您让我注意到这一点。我现在修改了上面的最后一个脚本,对文件进行预处理,将文件分成列,进行平均,并将结果通过管道传输到单独的管道文件(mkpipe)。然后,粘贴程序将分别运行,并从所有管道读取输入并合并它们。唯一需要注意的是,所有管道都必须合理地同时写入,否则一个管道将填充并暂停输入到其他管道,所有操作都将停止。我要发布它吗?我打算建议将其发布到codereview.stackexchange.com,但不记得我是如何让其他S.E.相关网站使用我的openID的
$ cmd1=(cat $f)
$ cmd2=(tac $f)
$ paste <("${cmd1[@]}") <("${cmd2[@]}")
A B C   G H I
D E F   D E F
G H I   A B C
cols=$(head -n 1 $f|wc -w)
for (( i=1 ; i<=cols ; i++ )); do
  cmd[i]="<(cat $f|cut -f$i|Some_Complicated_Analysis)"
done
eval paste "${cmd[*]}"   # quotes are important here
{
  cat -<<EOS
10 7.74336e-08 7.30689e-08 0.359106        19.981796       -0.160611       0.027
10 7.74336e-08 7.30689e-08 0.363938        19.985069       0.041319        0.035
10 7.74336e-08 7.30689e-08 0.363133        19.982094       0.041319        0.068
10 7.74336e-08 7.30689e-08 0.360716        19.981796       -0.160611       0.006
10 7.74336e-08 7.30689e-08 0.361522        19.981796       0.243249        0.049
10 7.74336e-08 7.30689e-08 0.357897        19.986260       0.041319        0.035
EOS
} |
awk '
  BEGIN { binSz=3; binSzLim=binSz ; binSzLim++ }
  NR==1{
    # base error checking on number of cols in first record
    maxCols=NF
    maxColsLim=maxCols ; maxColsLim++
    r=0
  }
  {
    if (NF != maxCols) {
      print "Skipping record, Mismatch in data, expected " maxCols ", found " NF " recs at " NR ":" $0
      next
    }
    r++
    #dbg print "r="r" NR=" NR ":$0=" $0

    # load data into temp arr[] by column
    for (c=1;c<maxColsLim;c++) {
      arr[r,c]+=$c
      #dbg printf ("arr["r","c"]=" arr[r,c] " " )

      avgArr[r,c]++
      #dbg print "avgArr["r","c"]="avgArr[r,c]
    }

    if(r>=binSz) {
      r=0
    }
  }
  END {
    for (r=1;r<binSzLim;r++) {
      #dbg print "r=" r " binSzLim=" binSzLim " " (r<binSzLim) "\t"
      for (c=1;c<maxColsLim;c++) {
        #dbg printf("arr["r","c"]=" arr[r,c] "\tavg=" arr[r,c]/binSz "\t")
        printf(  arr[r,c]/avgArr[r,c] " ")
      }
      printf "\n"
    }
  }
'
10 7.74336e-08 7.30689e-08 0.359911 19.9818 -0.160611 0.0165
10 7.74336e-08 7.30689e-08 0.36273 19.9834 0.142284 0.042
10 7.74336e-08 7.30689e-08 0.360515 19.9842 0.041319 0.0515