일련의 문자열이 있습니다. 이는 "노드"라고 표시된 작은 문자열로 구성되며 때로는 단독으로, 때로는 문자 :
나 연결 로 구성됩니다 ,
.
더 큰 문자열("제목")을 "노드"로 분할하고 싶습니다.
>
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(코어)
- 커널: 리눅스 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/gp
g
: 모두( 마지막 때문에 모두 ),
또는:
개행( )을 바꾸고 인쇄(\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
(그렇지 않은 경우 보다 완전한 입력 예제를 제공해야 합니다).
문자열이 실제로 file 에 있다고 가정하면 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
이러한 "노드"가 하나만 포함된 행을 건너뛰려면 명령을 다음과 같이 수정할 수 있습니다.
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
작업 방법:
- 최소한 두 개의 노드를 포함하는 라인과 노드가 시작하는 라인만
>NODE_
"흥미로운" 라인이라고 부르겠습니다. 흥미로운 줄이 나타날 때마다>;:,'
개행 문자로 변경합니다. - 그런 다음 세미콜론으로 끝나지 않는 경우를 대비하여 관심 있는 줄에 개행 문자를 추가합니다. 이
D
명령은 암시적 루프를 시작하고 sed 코드의 첫 번째 줄로 이동합니다. - 첫 번째 줄은 모든 작업이 발생하는 곳이며, sed가 한 줄에 하나씩 노드를 연속적으로 출력하는 동안 흥미로운 줄이 완전히 소비됩니다.