根据字符串的开头有条件地替换bash字符串中的模式

时间:2016-01-17 01:00:16

标签: sed

我是bash的新手,请原谅我,如果不使用正确的条款。

我需要在一组文件中替换六个字符的某些模式。模式的顺序取决于每个文本字符串的开头。

这是输入的一个例子:

chr1:123-123 5GGGTTAGGGTTAGGGTTAGGGTTAGGGTTA3

chr1:456-456 5TTAGGGTTAGGGTTAGGGTTAGGGTTAGGG3 

chr1:789-789 5GGGCTAGGGTTAGGGTTAGGGTTA3

chr1:123-123等是字符串的名称,它们与我需要通过选项卡处理的字符串分开。我需要使用的字符串由字符5和3分隔,但我可以更改它们。

我希望所有订单中包含TAG的所有模式都替换为XTTAGGG,{{1} },TAGGGAGGGTTGGGTTAGGTTAG

类似地,包含GTTAGG的模式(如第3行)的顺序与前一个类似,将替换为不同的字符。 对于构成每个模式的所有6个字符,重复游戏并具有一些特定的差异。 我开始写这样的东西:

CTAGGG

说明

#!/bin/bash
NORMAL=`echo "\033[m"`
RED=`echo "\033[31m"` #red

#read filename for the input file and create a copy and a folder for the output
read -p "Insert name for INPUT file: " INPUT
echo "Creating OUTPUT file " "${RED}"$INPUT"_sub.txt${NORMAL}"
mkdir -p ./"$INPUT"_OUTPUT
cp $INPUT.txt ./"$INPUT"_OUTPUT/"$INPUT"_sub.txt
echo 
#start the first set of instructions
perfrep
#starting a second set of instructions to substitute pattern with one difference from TTAGGG
onemism

我还需要重复perfrep() { sed -i -e 's/TTAGGG/X/g' ./"$INPUT"_OUTPUT/"$INPUT"_sub.txt sed -i -e 's/TAGGGT/X/g' ./"$INPUT"_OUTPUT/"$INPUT"_sub.txt sed -i -e 's/AGGGTT/X/g' ./"$INPUT"_OUTPUT/"$INPUT"_sub.txt sed -i -e 's/GGGTTA/X/g' ./"$INPUT"_OUTPUT/"$INPUT"_sub.txt sed -i -e 's/GGTTAG/X/g' ./"$INPUT"_OUTPUT/"$INPUT"_sub.txt sed -i -e 's/GTTAGG/X/g' ./"$INPUT"_OUTPUT/"$INPUT"_sub.txt } # starting a second set of instructions to substitute pattern with one difference from TTAGGG onemism(){ sed -i -e 's/[GCA]TAGGG/L/g' ./"$INPUT"_OUTPUT/"$INPUT"_sub.txt sed -i -e 's/G[GCA]TAGG/L/g' ./"$INPUT"_OUTPUT/"$INPUT"_sub.txt sed -i -e 's/GG[GCA]TAG/L/g' ./"$INPUT"_OUTPUT/"$INPUT"_sub.txt sed -i -e 's/GGG[GCA]TA/L/g' ./"$INPUT"_OUTPUT/"$INPUT"_sub.txt sed -i -e 's/AGGG[GCA]T/L/g' ./"$INPUT"_OUTPUT/"$INPUT"_sub.txt sed -i -e 's/TAGGG[GCA]/L/g' ./"$INPUT"_OUTPUT/"$INPUT"_sub.txt } T[GCA]AGGGTT[TCG]GGGTTA[ACT]GGTTAG[ACT]G

使用此程序,我得到显示的输入

的结果
TTAGG[ACT]

在我看来,对于我的工作,第一个和第二个字符串都由X重复制作五次,字符的顺序略有不同。另一方面,第三个可能会被掩盖:

5GGGXXXXTTA3

5XXXXX3 

5GGGLXXTTA3

如何告诉脚本如果字符串以5GGGTTA而不是5TTAGGG开头,则必须用

替换
5LXXX3

而不是

sed -i -e 's/GGGTTA/X/g' ./"$INPUT"_OUTPUT/"$INPUT"_sub.txt

我需要重复所有案件;例如,如果字符串以GTTAGG开头,我将需要以

开头
sed -i -e 's/TTAGGG/X/g' ./"$INPUT"_OUTPUT/"$INPUT"_sub.txt

等等,并添加了我的模式的几种变体。

我需要使用sed -i -e 's/GTTAGG/X/g' ./"$INPUT"_OUTPUT/"$INPUT"_sub.txt 和输入文件的所有行的变体重复替换。

对不起这个问题很抱歉。谢谢大家。

添加Varun提供的信息。

6个字符的模式为TTAGGGTTAGGG[GCA]TAGGGT[GCA]AGGGTT[TCG]GGGTTA[ACT]GGTTAG[ACT]G 。 必须检查每个帧的不同,例如TTAGG[ACT]我们有6帧TTAGGGTTAGGGGTTAGGGGTTAG,{{1} },GGGTTA。 必须将相同的帧应用于包含可变位置的图案。

我将总共检查42种模式,分为7组:一组包含AGGGTT和衍生框架,6包含具有可变位置的模式及其衍生物。 TAGGGT和衍生物是最重要的,需要先检查。

1 个答案:

答案 0 :(得分:1)

#! /usr/bin/awk -f

# generate a "frame" by moving the first char to the end
function rotate(base){ return substr(base,2) substr(base,1,1) }

# Unfortunately awk arrays do not store regexps 
# so I am generating the list of derivative strings to match
function generate_derivative(frame,arr,  i,j,k,head,read,tail) {
    arr[i]=frame;
    for(j=1; j<=length(frame); j++) {
        head=substr(frame,1,j-1);
        read=substr(frame,j,1);
        tail=substr(frame,j+1);
        for( k=1; k<=3; k++) {
           # use a global index to simplify
            arr[++Z]= head substr(snp[read],k,1) tail
        }
    }
}

BEGIN{
    fs="\t";
   # alternatives to a base
   snp["A"]="TCG"; snp["T"]="ACG"; snp["G"]="ATC";  snp["C"]="ATG"; 

    # the primary target
    frame="TTAGGG";
    Z=1; # warning GLOBAL
    X[Z] = frame;
    # primary derivatives
    generate_derivative(frame, X);
    xn = Z;

    # secondary shifted targets and their derivatives
    for(i=1; i<length(frame); i++){
        frame = rotate(frame);
        L[++Z] = frame;
        generate_derivative(frame, L);
    }
}

/^chr[0-9:-]*\t5[ACTG]*3$/ {

    # because we care about the order of the prinary matches
    for (i=1; i<=xn; i++) {gsub(X[i],"X",$2)}
    # since we don't care about the order of the secondary matches
    for (hit in L) {gsub(L[hit],"L",$2)}
    print
}
END{
    # print the matches in the order they are generated
    #for (i=1; i<=xn; i++) {print X[i]};
    #print ""
    #for (i=1+xn; i<=Z; i++) {print L[i]};
}

IFF您可以生成一个静态匹配顺序,然后您可以使用它 像上面的Awk脚本可以工作。但是你说主要模式应该优先,并且在某些情况下首先应该更好地应用次要规则。 (没有办法)。

如果你需要一个更灵活的匹配模式,我建议你看看&#34;带有回溯的递归正常解析&#34;或者&#34;解析表达式语法&#34;。 但是你不再是一个bash shell了。