ㅏ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는 포함하지 않음.
두 키워드 사이의 텍스트(두 단어 제외)를 읽을 수 있지만 시작 단어는 포함하고 끝 단어는 제외하는 방법을 모르겠습니다.
conf[0]
또한 각 형태를 = 첫 번째 형태, = 두 번째 형태 등과 같은 배열로 읽는 것은 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과 같이 한 번에 한 바이트를 읽지 않기 때문에 실패했습니다 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"