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(코어)
  • 커널: 리눅스 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(그렇지 않은 경우 보다 완전한 입력 예제를 제공해야 합니다).

문자열이 실제로 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가 한 줄에 하나씩 노드를 연속적으로 출력하는 동안 흥미로운 줄이 완전히 소비됩니다.

관련 정보