2011-09-01 69 views
1

我想连接两个或多个文件,具体取决于名称是否包含数组中的元素。Bash:基于数组变量的猫

我逐行读取这种文件线(proteome.pisa):

2PJY_p chain=(B C) hresname=() hresnumber=() hatom=() model=() altconf=() 
2Q7N_p chain=(A E F G H I J K L) hresname=(FUC MAN NAG) hresnumber=() hatom=() model=() altconf=() 

对于每一线,所述脚本提取在第一列中的字符串并把它定义为可变PDBID。然后它接受第二列并将其定义为数组(元素链$ c)。然后它检查是否存在名为$ {pdbid} _ $ {c} _p.pdb的文件,如果存在,它会将其内容合并到文件$ {pdbid} _p _ $ {chains} .pdb

这是脚本:

while read line ; do 

echo "$line" > pdb.line 
cut -f1 pdb.line > pdb.list 
sed -i 's/.*/\"&\"/' pdb.list 
sed -i 's/_p//g' pdb.list 
awk '{ printf "pdbid="; print }' pdb.list > pdbid.list 

cut -f2 pdb.line > chain.list 

source pdbid.list 
source chain.list 

chains=`printf "%s" "${chain[@]}"` 

for c in ${chain[@]} ; do 
if [ ${#chain[@]} -gt 1 ] && \ 
    [ -f ${pdbid}_${c}_p.pdb ] ; then 
cat ${pdbid}_${chain[$c]}_p.pdb >> ${pdbid}_p_${chains}.pdb 
fi 
done 

done < proteome.pisa 

预期的行为是合并,例如,第一行,2PJY_p_B.pdb和2PJY_p_C.pdb在一个名为2PJY_p_BC.pdb文件。但是,它实际上是将第一个文件合并两次。我不明白为什么...

+1

你使用'set -vx'来帮助调试变量的值吗?祝你好运。 – shellter

回答

1

这是一个很好的问题,因为它证明了bash不能单独做所有事情。相反,它需要帮助者,比如awk,cut,...我翻遍了你的解决方案,看起来在两行之后,你期望有变量pdbid,chain和chain set。但是,您的脚本没有正确设置它们,我可以帮助完成该部分。我不太了解Perl,但认为Perl在这种情况下会很好地工作。这里是makevars.pl

while (<STDIN>) { 
    my($line) = $_; 
    if ($line =~ /^(.*)_p.*chain=\((.*)\).*hresname.*$/) { 
     print "pdbid=$1\n"; 
     print "chain=($2)\n"; 
     $chains = $2; 
     $chains =~ s/ //g; 
     print "chains=$chains\n"; 
    } 
} 

这里是shell脚本:

while read line 
do 

    echo "$line" | perl makevars.pl >setvars.sh 
    source setvars.sh 
    # Now, pdbid, chain, and chains are set, do your things 

done < proteome.pisa 

我希望这有助于。

+0

感谢这个perl解决方案。我会试一试。 – mirix

0

的问题似乎是在这条线的阵列的定义:

cat ${pdbid}_${chain[$c]}_p.pdb >> ${pdbid}_p_${chains}.pdb 

改变它来:

cat ${pdbid}_${c}_p.pdb >> ${pdbid}_p_${chains}.pdb 

出现解决该问题。

另外,我有双引号的所有的 “$ {链[@]}”。

1

我建议预处理输入到一个简单的形式与sed,然后过来就是循环。这是假设chain=(...)始终是一条线上的第一个这样的属性。

#!/bin/sh 

# Replace 2ICQ_p chain=(A B C ... Z) attribs= ... with 
# 2ICQ_p A B C ... Z 
sed 's/ chain=\(//;s/\).*//' <proteome.pisa | 
while read pdbid chain; do 
    chains=${chain/ /} 
    for c in $chain; do 
     test -e ${pdbid}_${c}_p.pdb || continue 
     cat ${pdbdid}_${c}_p.pdb 
    done >${pdbid}_p_${chains}.pdb 
done 

这样可以避免使用临时文件,这些临时文件会使您的第一个脚本发生障碍;如果不是令人担忧的话,找到一个生成的文件也看起来相当惊人(通常你可以使用反引号来解决这类问题,但这里并不需要)。

sed有多种变体;有些(例如Linux)希望将一个字面括号进行反斜杠,而另一些(例如Mac OSX)则不需要。如果这不起作用,请尝试取出反斜杠。

read具有多个变量名将输入分割为空白,以便第一个变量名接收第一个标记等;最后一个命名的变量接收剩下的任何东西,没有额外的空白分割。 continue跳转到封闭forwhile循环的下一次迭代。除此之外,这应该是不言自明的。如果你真的被迫在纯Bourne shell中完成这项工作,那么开头的sed替换可能可以替换为涉及字符串替换的内容。