我正在尝试对多列文件的每一列执行分析,并使用粘贴一起重新加入列。我不知道先验有多少列,所以我用“wc -w”和一个循环来定义一个命令数组。然后每个命令都是一个进程替换。以下脚本显示了我正在尝试的内容,输出显示在之后。值得注意的是,如果我将命令数组回显到终端,那么,使用鼠标进行剪切粘贴,它可以正常工作,因此它必须是变量扩展和进程替换的顺序。
简而言之,我需要在 shell变量中进行进程替换。有任何想法吗?提前谢谢。
-------------- script.sh ----------------
#!/bin/bash
f="file.txt";
echo "File contents"
cat $f;
# simple solution
echo; echo "First try";
paste <(cat $f) <(tac $f)
# now define cmd[1] and cmd[2] and merge together with paste
echo; echo "Second try";
cmd[0]="paste";
cmd[1]="cat $f";
cmd[2]="tac $f";
${cmd[0]} <(${cmd[1]}) <(${cmd[1]})
# but what I really want is something like:
echo; echo "Third try";
cmd[1]="<(cat $f)";
cmd[2]="<(tac $f)";
${cmd[0]} ${cmd[1]} ${cmd[2]}
# or even better:
echo; echo "Fourth try";
${cmd[*]}
echo; echo "Show the array";
echo ${cmd[*]}
-------------输出--------------------
$ ./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
$
在回复shellter时,这里有一些示例输入。
7.74336e-08 7.30689e-08 0.359106 19.981796 -0.160611 0.027
7.74336e-08 7.30689e-08 0.363938 19.985069 0.041319 0.035
7.74336e-08 7.30689e-08 0.363133 19.982094 0.041319 0.068
7.74336e-08 7.30689e-08 0.360716 19.981796 -0.160611 0.006
7.74336e-08 7.30689e-08 0.361522 19.981796 0.243249 0.049
7.74336e-08 7.30689e-08 0.357897 19.986260 0.041319 0.035
这样的数据可能有1亿行。我需要将每列分开,将每列分成(比方说)1000块,然后执行块中每个元素的平均值,然后将平均列重新合并在一起。对于下面的例子,如果我平均只有2个块,每个3个元素(而不是100K,每个1000),那么第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
我已经有程序进行平均(即“Some_Complicated_Analysis”)并且它工作正常。因此,我需要为脚本分离列,将其提供给Some_Comp_Analysis,然后使用paste
将各种输出再次合并回列中。但是,这些文件很大,而且我不知道它有多少列。如果我知道只有2列,那么paste <(${cmd[1]}) <(${cmd[2]})
就可以了。
解决方案
更新:已找到答案 - 如下面的glenn jackman的回复更新所示。 paste
命令必须以eval
开头。我不确切知道为什么这是必要的,但没有它们,变量扩展${cmd[]}
会混淆过程替换<(...)
。上面的答案还在数组扩展"${cmd[*]}"
周围加上双引号,但这些看起来并不那么重要 - 尽管如果没有它们,cmd[]
内的其他扩展可能会失败。但是,eval
是必要的。
答案 0 :(得分:3)
将“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
更新:您只需要eval
构建的流程替换:
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
答案 1 :(得分:1)
如果您的脚本仍然无效,这可能会更有帮助。仍然遵循glenn jackman的回答,但另外你可能想在剧本中做到这一点
设置+ o posix
http://www.linuxjournal.com/content/shell-process-redirection
来自链接: “流程替换不符合POSIX标准,因此可能必须通过以下方式启用:set + o posix”
答案 2 :(得分:0)
试试这个:
{
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
我在数据中添加了第一列10,以便于调试总和和平均值正常工作。
一个有趣的问题,感谢发布并感谢您继续回答我的问题的良好意愿;-)
{ cat -<<EOS ... EOS }|
只是为了让整个事情在一个副本/粘贴中运行变得容易,并且看到它正在运行。您可以将awk代码放在顶部#!/bin/awk -f
的{{1}}文件中,并将其作为chmod 755 myScript.awk
运行。
您只需要更改为BEGIN块中的myScript.awk BigFile > AvgsFile
即可按预期处理文件。
我很想知道这个版本的时间安排。