awk出力を介したループ

awk出力を介したループ

一連の文字列があります。これは「ノード」とマークされた小さな文字列で構成され、時には単独で、時には文字または:接続で構成されます,

大きな文字列(「タイトル」)を「ノード」に分割したいです。

>sedを使用していくつかの追加文字(、、、;)を削除し、'awkを使用して残りの文字列を分割し:ます。,

問題は、最初のawk列だけでなく出力(「ノード」)を繰り返すことです。私は{print $0}awkを使ってみましたが、区切り文字などを使って初期文字列を印刷します。

助けてください?

入力例(例ではforループによって処理され、より大きなコードではif / elseの出力です):

>NODE_3028138_length_2215_cov_1.9513_ID_6056275:NODE_6264558_length_375_cov_4.0000_ID_12529115';
>NODE_4338305_length_1150_cov_1.0000_ID_8676609;
>NODE_3552704_length_509_cov_1.0000_ID_7105407:NODE_4456634_length_439_cov_1.9597_ID_8913267',NODE_4457268_length_491_cov_0.9657_ID_8914535';

出力例(スタンドアロンなので、ノードNODE_4338305なし):

NODE_3028138_length_2215_cov_1.9513_ID_6056275
NODE_6264558_length_375_cov_4.0000_ID_12529115
NODE_3552704_length_509_cov_1.0000_ID_7105407
NODE_4456634_length_439_cov_1.9597_ID_8913267
NODE_4457268_length_491_cov_0.9657_ID_8914535

NODE_3028138_length_2215_cov_1.9513_ID_6056275理想的には上記の各項目(、その後NODE_6264558_length_375_cov_4.0000_ID_12529115など)を繰り返したいと思います。

for i in ">NODE_3028138_length_2215_cov_1.9513_ID_6056275:NODE_6264558_length_375_cov_4.0000_ID_12529115';" \
">NODE_4338305_length_1150_cov_1.0000_ID_8676609;" \
">NODE_3552704_length_509_cov_1.0000_ID_7105407:NODE_4456634_length_439_cov_1.9597_ID_8913267',NODE_4457268_length_491_cov_0.9657_ID_8914535';"
do      
if [[ $i == *":"* ]];         
then 
echo $i            
i=$(sed "s/[>;\']//g" <<< $i);            
echo $i
echo $i | awk -F '[:,]' '{print $1}' | while IFS= read -r line; do echo "$line"; done
fi; done

オペレーティングシステム情報を追加するには編集してください。

  • オペレーティングシステム:CentOS Linux 7(コア)
  • カーネル: Linux 3.10.0-1127.el7.x86_64
  • アーキテクチャ:x86-64

答え1

どのステップも表示する必要はありません。私が正しく理解した場合は、次の形式のfastaファイルセットから始めます。

>header
sequence

>ヘッダーを抽出してすべてのコンテンツを削除してから、またはに'分割しようとしています。その場合は、fastaファイル自体で直接これを行うことができます。,;

$ sed -n '/^>/{s/>//; s/[,:]/\n/gp}' *.fasta | tr -d "';"
NODE_3028138_length_2215_cov_1.9513_ID_6056275
NODE_6264558_length_375_cov_4.0000_ID_12529115
NODE_3552704_length_509_cov_1.0000_ID_7105407
NODE_4456634_length_439_cov_1.9597_ID_8913267
NODE_4457268_length_491_cov_0.9657_ID_8914535

説明する

  • sed -n:明示的に指示しない限り、通常の出力を抑制し、何も印刷しません。
  • /^>/{something}:行が始まると>実行しますsomething
  • s/^>//;>:行の先頭から削除します。
  • s/[,:]/\n/gpg:すべて(最後のためすべて),または:改行()を置き換えて印刷(\n最後のために印刷します)。p
  • tr -d "';";またはいずれかを削除します'

あなたの意見では、試してみましたが、'i=$(sed "s/[:,]/\n/g" <<< $i)'改行ではなく空白だけが得られたと言いました。その理由は、echo $i代わりに実行してecho "$i"改行文字が失われるからです。


表示された文字列コレクションを使用してこれを行う必要がある場合は、次のことができます。

for i in ">NODE_3028138_length_2215_cov_1.9513_ID_6056275:NODE_6264558_length_375_cov_4.0000_ID_12529115';" ">NODE_4338305_length_1150_cov_1.0000_ID_8676609;" ">NODE_3552704_length_509_cov_1.0000_ID_7105407:NODE_4456634_length_439_cov_1.9597_ID_8913267',NODE_4457268_length_491_cov_0.9657_ID_8914535';"; do 
    sed -n '/^>/{s/>//; s/[,:]/\n/gp}' <<<"$i" | tr -d "';" ; 
done
NODE_3028138_length_2215_cov_1.9513_ID_6056275
NODE_6264558_length_375_cov_4.0000_ID_12529115
NODE_3552704_length_509_cov_1.0000_ID_7105407
NODE_4456634_length_439_cov_1.9597_ID_8913267
NODE_4457268_length_491_cov_0.9657_ID_8914535

答え2

次の解決策はやや粗雑ですが、効果があります。例入力に示すように、すべてのノードが文字列で始まるとしますNODE(そうでない場合は、より完全な入力例を提供する必要があります)。

文字列が実際にファイルにあると仮定すると、input.txt次のawk呼び出しはトリックを実行します。

awk '{gsub(/[:>,;\047]/,""); n=split($0,a,/NODE/); for (i=2;i<=n;i++) printf("NODE%s\n",a[i])}' input.txt
  • gsub()これは最初にすべての「追加」文字を(\047一重引用符で置き換え、コマンド自体が一重引用符内にある'ため、コマンドラインに文字どおりに配置することはできません。)awk
  • 次に、残りの文字列をパターンのフィールドに分割し、NODE結果を配列に保存しますa
  • その後、最初の項目以外のすべての「フィールド」(つまり、最初の項目より前の文字列NODE)が前に追加され、個別に印刷されますNODE

サンプル入力の結果は次のとおりです。

awk '{gsub(/[:>,;\047]/,""); n=split($0,a,/NODE/); for (i=2;i<=n;i++) printf("NODE%s\n",a[i])}' input.txt
NODE_3028138_length_2215_cov_1.9513_ID_6056275
NODE_6264558_length_375_cov_4.0000_ID_12529115
NODE_4338305_length_1150_cov_1.0000_ID_8676609
NODE_3552704_length_509_cov_1.0000_ID_7105407
NODE_4456634_length_439_cov_1.9597_ID_8913267
NODE_4457268_length_491_cov_0.9657_ID_8914535

これらの「ノード」が1つだけ含まれる行をスキップするには、コマンドを次のように変更できます。

awk '{gsub(/[:>,;\047]/,""); if ((n=split($0,a,/NODE/))<3) next; for (i=2;i<=n;i++) printf("NODE%s\n",a[i])}' input.txt
NODE_3028138_length_2215_cov_1.9513_ID_6056275
NODE_6264558_length_375_cov_4.0000_ID_12529115
NODE_3552704_length_509_cov_1.0000_ID_7105407
NODE_4456634_length_439_cov_1.9597_ID_8913267
NODE_4457268_length_491_cov_0.9657_ID_8914535

答え3

以下のPythonメソッドを試してください。

#!/usr/bin/python
import re
m=re.compile(r'[:;,]')
k=open('filename','r')
for i in k:
    co=i.count("NODE")
    if co > 1:
        q=i.strip()
        k=re.sub(m,"\n",q)
        print k.strip().replace("'","").replace(">","")

出力

NODE_3028138_length_2215_cov_1.9513_ID_6056275
NODE_6264558_length_375_cov_4.0000_ID_12529115
NODE_3552704_length_509_cov_1.0000_ID_7105407
NODE_4456634_length_439_cov_1.9597_ID_8913267
NODE_4457268_length_491_cov_0.9657_ID_8914535

awk:最高のソリューションはすでにawkで利用可能です。これは私の試みだけです。

awk '{print $0,gsub("NODE",$0)}' filename| awk '$NF >1 {print $1}'| sed "s/[;:,]/\n/g"|sed '/^$/d'| sed "s/[\>']//g"

答え4

sedエディタを使用すると、次のように必要な出力を生成できます。

sed \
  -e '/\n/{/^\n/!P;D;}'                    \
  -e "/^>NODE_.*NODE/ y/>;:,'/\n\n\n\n\n/" \
  -e '/\n/G;D'                             \
file

結果:

NODE_3028138_length_2215_cov_1.9513_ID_6056275
NODE_6264558_length_375_cov_4.0000_ID_12529115
NODE_3552704_length_509_cov_1.0000_ID_7105407
NODE_4456634_length_439_cov_1.9597_ID_8913267
NODE_4457268_length_491_cov_0.9657_ID_8914535

作業方法:

  • 少なくとも2つのノードを含む行と、ノードが開始する行だけを>NODE_ 「興味深い」行と呼びます。興味深い行が表示されるたびに>;:,'改行文字に変更します。
  • 次に、セミコロンで終わらない場合に備えて、興味のある行に改行文字を追加します。このDコマンドは暗黙的なループを開始し、sedコードの最初の行に移動します。
  • 最初の行はすべてのタスクが発生する場所であり、sedが1行に1つずつノードを連続して出力している間、興味深い行が完全に消費されます。

関連情報