ㅏPDBファイルには、タンパク質構造に関する多くの詩が含まれています。
各形式はキーワードで始まります。原子キーワードで終わる終わり。
ATOMからENDまでのすべての行を読むことができるように、bashからファイルを読み取ろうとしますが、ENDという単語を読みたくありません。
各フォーム(段落)に対してこれを行い、各段落を配列に保存したいと思います。
ファイルは次のようになります。
ATOM line 1...
ATOM line 2...
ATOM line 3...
# More lines....
END
ATOM line 1...
ATOM line 2...
ATOM line 3...
# more lines...
END
一つ原子到着終わり形態である。
各型を配列で読み取ることができるようにしたい。ATOMは含むがENDは含まない。
2つのキーワードの間のテキスト(2つの単語を除く)を読み取ることができますが、開始単語は含まれ、終了単語は除外する方法がわかりません。
conf[0]
また、各形式を=最初の形式、=2番目の形式などの配列に読み込むことはconf[1]
機能しません。
パスワード:
#!/bin/bash
filename='coor.pdb'
echo Start
i=0
while read line; do
conf[$i]=$(sed -n '/ATOM/,/END/{//!p}')
i=i+1
done < $filename
echo $conf[0] > first_frame.data
答え1
#!/bin/bash
filename='coor.pdb'
echo Start
i=1
input=false
while read -r line
do
if [ "${line%% *}" == "ATOM" ]
then
input=true
elif [ "${line%% *}" == "END" ]
then
((i++)) # increase variable i by 1 == (i+1)
rm -f "${i}_frame.data" # remove ${i}_frame.data" if exist
input=false # stop output lines until next ATOM
fi
if $input # if var INPUT is true add line to ${i}_frame.data file
then
echo "$line" >> "${i}_frame.data"
fi
done < "$filename"
未来のためにsedヒント:
sed '/ATOM/,/END/!d;/END/d'
sed -n '/ATOM/{:;N;s/\nEND//;T;p}'
したがって、次の操作を実行できます。
nl -s'.frame.data' -b p"^END" coor.pdb |
sed -n '/ATOM/{s/^/echo \"/;:;s/ \{6,\}//;N;s/END//;T;s/\n */\">/p}' |
bash
答え2
Bashのテキスト処理が遅い。純粋なbash文字列操作は、すでに変数にあるテキストまたは非常に小さなファイルを読み取るのに役立ちます。コンピュータ生物学ファイルは一般にそれほど小さくないため、このようなツールを使用するための開始コストはawk
最小限に抑えられますが、テキスト処理はbashよりはるかに高速です。
実際にファイルを分割したいと仮定すると、次のようになりますpdb
。
awk -v RS='\nEND\n' '{ fn="frame" NR ".pdb"; print > fn; close(fn) }' "$filename"
awkに\nEND\n
改行の代わりに入力レコード区切り文字を使用させ、レコードカウンタを使用することもできます。出力レコード区切り文字はまだデフォルトですORS="\n"
。 (Costasが非常に良い提案をしました。行の先頭になるようにEND
修正し、フォームのclose
多い入力にファイル記述子をあまり使用しないように追加しました。)
私の最初の考えは次のとおりです。
awk 'BEGIN{i=0; fn="frame0.pdb"}
!/^END/ { print > fn; }
/^END/{ close(fn); fn="frame" ++i ".pdb"; }' \
"$filename"
awkはファイルハンドルをキャッシュするので、print > fn
ファイルを何度も閉じてもファイルは再開されません。 (close(fn)
そうします。効率のためにのみ存在するので、awkは最終的に多くのファイルを開きません。)
ロジックは次のとおりです。各行全体を現在のファイル名で印刷します。行が表示されたら、END
次のファイル名に移動します。最後の行の後に他の行がない場合、新しいEND
ファイル名は記録されず、残りの最後のファイルも生成されません。
OTOH、メモリ内の行ブロック配列で操作を実行したい場合:
# add a `!/^END/` condition to the concat block if you want to avoid a stray newline after each END
awk 'BEGIN{i=0}
!/^END/ { arr[i] = arr[i] $0 "\n"; } # concat onto this array element
/^END/ { i++; }
END{for (k in arr) { print arr[k]; > ("frame" k ".pdb") } }' \
"$filename"
その後、ブロックのawk行配列を使用して必要な操作をすべて実行できますEND
。正規表現機能に優れています。
sed
bashを使用してsedを駆動しようとしましたが失敗しました(nvm、shellなど、一度に1バイトを読み取らないため失敗しましたread
):
i=0
while true; do
outf="frame${i}.data";
##### DON'T USE THIS, sed READS TOO MUCH #####
strace -o sed.tr sed '/^END/q42' > "$outf"; # strace to see that the 2nd sed invocation finds the file empty
ret=$?;
((i++));
if [[ $ret == 0 ]];then # sed didn't see END before EOF
[[ -s $outf ]] || rm -f "$outf"; # clean up empty last file
break;
elif [[ $ret != 42 ]]; then
echo some other sed error;
break;
fi;
done < "$filename"