如何防止while循环输出与先前的输出发生冲突?

时间:2019-05-28 18:20:47

标签: bash

第一次通过while循环后,第二次通过的输出将追加到第一次通过的最后一行。

在这里,我正在使用bash的while循环,我怀疑这是一个\ n问题。

有两个文件,每个都有一个:

input1
CGTGGGAA
TGTGGGAA
CGTGAGAA
namePBM
AAAAAACAACAGGAGGGCATCATGGAGCTGTCCAGCCTGT    220.632711
AAAAAACAGCCGGATCACAATTTTGCCGAGAGCGACCTGT    221.514925
AAAAAACGTCCGGTACACCCCGTTCGGCGGCCCAGCCTGT    222.473157
AAAAAACTCTAGACCTTTAGCCCATCGTTGGCCAACCTGT    262.183554

以下是相关的代码段:

while IFS= read -r line
do
    OutputA1+=$(grep -o -P "$line" "$namePBM") #Shows Target Site
    OutputA2+=$(grep -o -P ".{0,2}$line" "$namePBM" | sed 's/........$//') #5' Flank
    OutputA3+=$(awk -v pat="$line" '$1~pat {print $2}' "$namePBM") #Intensity Values 
done < "$input1"

OutputA4=$(paste <(echo "$OutputA1") <(echo "$OutputA2") <(echo "$OutputA3"))

echo "$OutputA4"

输出看起来像这样:

CGTGGGAA        AT      500.306264
CGTGGGAA        GA      216.029774
CGTGGGAA        GT      226.937170
CGTGGGAA        CA      283.247237
CGTGGGAA        CC      383.089073
CGTGGGAA        TA      243.455285
CGTGGGAA        C       631.194970
CGTGGGAA        CT      318.330615
CGTGGGAA        AC      211.895150
CGTGGGAA                840.522056
CGTGGGAA        AG      194.045824
CGTGGGAA        AA      193.686006
CGTGGGAA        TC      282.153144
CGTGGGAA        GC      207.303981
CGTGGGAA        CG      225.282407
CGTGGGAA        TG      220.369882
CGTGGGAATGTGGGAA        TTTC    298.320734329.953276
TGTGGGAA        AG      203.847257
TGTGGGAA        GA      242.392699
TGTGGGAA        GT      211.894931
TGTGGGAA        AA      199.040909
TGTGGGAA        TT      228.433316
TGTGGGAA        TG      236.023833
TGTGGGAA        AT      320.913155
TGTGGGAA        CG      252.373388
TGTGGGAA        GC      257.858672
TGTGGGAA        TA      224.919676
TGTGGGAA        GG      176.379573
TGTGGGAA        CA      211.450761
TGTGGGAA        AC      315.362784
TGTGGGAA                666.500440
TGTGGGAACGTGAGAA        CCAG    187.171859233.376637

预期输出应为TGTGGGAA,其相关数据形式应在下一行。

1 个答案:

答案 0 :(得分:2)

现在的简单答案是,您需要在循环的每次迭代结束时发出换行符。

默认情况下,我认为$()命令捕获会丢弃最后的换行符,然后这会导致行重叠。

添加&& echo ''可能就足够了:

while IFS= read -r line
do
  OutputA1+=$(grep -o -P "$line" "$namePBM" && echo '') #Shows Target Site
  OutputA2+=$(grep -o -P ".{0,2}$line" "$namePBM" | sed 's/........$//' && echo '') #5' Flank
  OutputA3+=$(awk -v pat="$line" '$1~pat {print $2}' "$namePBM" && echo '') #Intensity Values 
done < "$input1"

OutputA4=$(paste <(echo "$OutputA1") <(echo "$OutputA2") <(echo "$OutputA3"))

echo "$OutputA4"

事实上,不,$()会丢弃所​​有尾随行(例如@Gordon),所以我们只能离开

while IFS= read -r line
do
  OutputA1+=$(grep -o -P "$line" "$namePBM") #Shows Target Site
  OutputA1+=$'\n'
  OutputA2+=$(grep -o -P ".{0,2}$line" "$namePBM" | sed 's/........$//') #5' Flank
  OutputA2+=$'\n'
  OutputA3+=$(awk -v pat="$line" '$1~pat {print $2}' "$namePBM") #Intensity Values 
done < "$input1"
  OutputA3+=$'\n'

OutputA4=$(paste <(echo "$OutputA1") <(echo "$OutputA2") <(echo "$OutputA3"))

echo "$OutputA4"

出于调试目的,使用grep -n参数在找到匹配项的namePBM中打印行号也可能会有用。

要在单个sed中执行此操作,就是反省地狱:

while IFS= read -r line
do
  sed -n 's/^\(\([^ ]\{0,2\}\)\|[^ ]*\([^ ]\{2,2\}\)\)\('"$line"'\)[^ ]*[ ]*\( [^ ]*\).*$/\4 \2\3 \5/p' $namePBM
done

也就是说:

  • -n不会打印不匹配的行
  • 's用所有逃脱的事物代替
  • /捕获模式:
  • (\([^ ]\{0,2\}\)\|[^ ]*\([^ ]\{2,2\}\)\)第一个单词中最多2个字符,或者任意字符加上我们想要的2个字符
  • \('"$line"'\)退出并捕获我们想要的短语
  • [^ ]*丢弃该单词的其余部分
  • [ ]*丢弃所有多余的空格,直到下一个单词
  • ([^] *)完全捕获了前一个空格和第二个单词
  • .*$丢弃直到行尾
  • /\4 \2\3 \5替换为:测试词组,第二个单词(最多2个字符或恰好2个字符之前)
  • /p'打印(由于-n)

哦,您可以使用\S代替[^ ]\s代替[ ]

另一种方法是将我们想要的所有单词组合到一个变量中,然后仅进行一次sed,但这将使包含2个或更多模式的任何行都不再重复:

构建一个我作为练习保留的字符串,但为了显示它的工作原理:

lines="CGTGGGAA""\|""TGTGGGAA""\|""CGTGAGAA"
sed -n 's/^\(\([^ ]\{0,2\}\)\|[^ ]*\([^ ]\{2,2\}\)\)\('"$lines"'\)[^ ]*[ ]*\( [^ ]*\).*$/\4 \2\3 \5/p' $namePBM