主题中的退化位置

时间:2018-11-01 06:48:14

标签: bash shell syntax

我是编码和编写shell脚本的新手,可以在蛋白质序列文件中搜索基序并打印它们的位置(如果存在)。 但是这些图案的位置已经退化。

例如, 基序可以是(psi,psi,x,psi),其中psi =(I,L或V),x可以是20个氨基酸中的任何一个。

我将搜索一组序列以查找该基序的出现。但是,我的蛋白质序列是精确的序列,即它们没有歧义,例如:

>
MSGIALSRLAQERKAWRKDHPFGFVAVPTKNPDGTMNLMNWECAIPGKKGTPWEGGL

希望搜索fasta文件中存在的蛋白质序列中所有可能的基序精确实例。 我有一个粗糙的代码,我知道这是错误的。

#!/usr/bin/bash
x=(A C G H I L M P S T V D E F K N Q R W Y)
psi=(I L V)
alpha=(D E)
motif1=($psi,$psi,$x,$psi)

  for f in *.fasta ; do
    if grep -q "$motif1" <$f ; then   
         echo $f
         grep "^>" $f | tr -d ">"
         grep -v ">" $f | grep -aob "$motif1"
     fi
  done

感谢您的帮助。 提前致谢!

1 个答案:

答案 0 :(得分:0)

shell是编排其他工具的出色工具,但它并不是特别适合分析文件的内容。

一种常见的安排是使用Shell在一组文件上运行Awk,并改为在Awk中执行检测逻辑。 (其他流行的工具是Python和Perl;如果我要从头开始,我可能会用Python解决。)

无论脚本语言是什么,都应该avoid code duplication;重构以将参数放入变量中,然后使用这些参数运行代码,或者将功能移至某个函数,然后使用不同的参数进行调用。例如,

scan () {
    local f
    for f in *.fasta; do
        # Inefficient: refactor to do the grep only once, then decide whether you want to show the output or not
        if grep -q "$1" "$f"; then
            # Always, always use double quotes around file names
            echo "$f"
            grep "^>" "$f" | tr -d ">"
            grep -v ">" "$f" | grep -aob "$1"
        fi
    done
}

case $motif in
    1)     scan "$SIM_Type_1";;   # Notice typo in variable name
    2)     scan "$SIM_Type_2";;   # Ditto
    3)     scan "$SIM_Type_3";;   # Ditto
    4)     scan "$SIM_Type_4";;   # Ditto
    5)     scan "$SIM_TYPE_5";;   # Notice inconsistent variable name
    alpha) scan "$SIM_Type_alpha";;
    beta)  scan "$SIM_Type_beta";;
esac

您在声明_*Type_*变量(或者有时是*_TYPE_*-shell区分大小写,您可能应该对所有变量使用相同的大小写,以便于自己使用)数组,但是您显然正在尝试将它们用作常规标量。我只能猜测您打算使变量实际包含什么内容。但我猜你想要类似的东西

# These are strings which contain regular expressions
x='[ACGHILMPSTVDEFKNQRWY]'
psi='[ILV]'
psi_1='[IV]'
alpha='[DE]'
# These are strings which contain sequences of the above regexes
# The ${variable} braces are not strictly necessary, but IMHO help legibility
SIM_Type_1="${psi}${psi}${x}${psi}"
SIM_Type_2="${psi}${x}${psi}${psi}"
SIM_Type_3="${psi}${psi}${psi}${psi}"
SIM_Type_4="${x}${psi}${x}${psi}"
SIM_TYPE_5="${psi}${alpha}${psi}${alpha}${psi}"
SIM_Type_alpha="${psi_1}${x}${psi_1}${psi}"
SIM_Type_beta="${psi_1}${psi_1}.${x}${psi}"
# You had an empty spot here   ^ I guessed you want to permit any character?

如果您真的希望这些是数组,则访问数组内容的方法是"${array[@]}",但是那样就不会产生可以直接传递给grep或Awk的东西,所以我继续将它们声明为包含正则表达式的字符串。

但是要重申一下,Awk可能是一种更好的语言,所以我们将scan重构为Awk脚本。

# This replaces the function definition above
scan () {
    awk -v re="$1" '{ if (/^>/) label=$0
        else if (idx = match($0, re, result) {
            if (! printed) { print FILENAME; printed = 1 }
            print len + idx ":" result[0]
        }
        len += 1+length($0)  # one for the newline
      }
      # Reset printed if we skip to a new file
      FNR == 1 { printed = 0 }' *.fasta
}

这里的主要复杂之处在于重新实现grep -b字节偏移量计算。如果这不是绝对必要的(也许行号就足够了吗?),则可以将Awk脚本简化为更琐碎的脚本。

您使用grep -a暗示您的输入文件可能包含DOS换行符。我认为无论如何都可以正常工作。

此重构的直接好处是我们避免扫描可能很大的输入文件两次。我们只扫描一次文件,并在第一个匹配项上打印文件名。

如果您想使脚本更具通用性,那么这可能比以前的grep | tr解决方案更好。但是,如果脚本满足了您的需要,并且匹配项通常在输入文件的开头附近,或者输入文件不大,那么您也许根本就不想切换到Awk。

还请注意,就像您的grep逻辑一样,如果将序列拆分到FASTA文件中的多行中并且匹配恰好跨越了一个换行符,则此操作将无效。

最后,使脚本提示输入交互式内容是一种设计缺陷。我建议您改为接受用户选择作为命令行参数。

motif=$1

因此,您可以将其用作./scriptname alpha来对FASTA文件运行alpha正则表达式。

另一种可能的重构方法是将所有主题正则表达式读入稍微复杂一点的Awk脚本中,并以某种形式打印所有主题正则表达式,然后让您轻松地选择要实际检查的细节。如果您要处理大量数据,那么只循环一次就可以了。