셸을 사용하여 구분 기호를 기반으로 여러 열을 행으로 분할

셸을 사용하여 구분 기호를 기반으로 여러 열을 행으로 분할

다음과 같이 탭으로 구분된 파일이 있습니다.

cg13201342  F   ARNT;ARNT;ARNT;CTSK 3'UTR;3'UTR;3'UTR;TSS1500
cg05269359  F   SCN4B;SCN4B;SCN4B;SCN4B 3'UTR;3'UTR;3'UTR;Body
cg06018296  R   NEK3;NEK3;NEK3;NEK3 3'UTR;3'UTR;3'UTR;Body
cg05172994  F   WDR20;WDR20;WDR20;WDR20 3'UTR;3'UTR;3'UTR;Body

원하는 출력:

cg13201342  F   ARNT   3'UTR
cg13201342  F   ARNT   3'UTR
cg13201342  F   ARNT   3'UTR
cg13201342  F   CTSK   TSS1500
cg05269359  F   SCN4B  3'UTR
.
.

등.

나는 노력했다

awk 'BEGIN {
       FS = OFS = "\t"
     }
     {
       n = split($3, f, " *;*")
       for (i=1; i<=n; i++)
         print $1, f[i]
     }' probe-genes-regions >chk

그러나 이는 세 번째 열만 분할합니다. 마지막 열을 두 번째 열과 분리하고 세 번째 열의 첫 번째 필드와 마지막 열의 첫 번째 필드 등으로 별도의 행을 형성하고 싶습니다.

답변1

예를 들어 필드 3과 4를 세미콜론을 사용하여 별도의 배열로 분할하고 반복합니다(필드 3과 4의 요소 수가 동일하다고 가정).

파싱.awk

BEGIN { OFS = "\t" }

{ 
  n = split($3, a, /;/); split($4, b, /;/)
  for(i=1; i<=n; i++)
    print $1, $2, a[i], b[i] 
}

다음과 같이 실행하세요:

awk -f parse.awk infile

산출:

cg13201342      F       ARNT    3'UTR
cg13201342      F       ARNT    3'UTR
cg13201342      F       ARNT    3'UTR
cg13201342      F       CTSK    TSS1500
cg05269359      F       SCN4B   3'UTR
cg05269359      F       SCN4B   3'UTR
cg05269359      F       SCN4B   3'UTR
cg05269359      F       SCN4B   Body
cg06018296      R       NEK3    3'UTR
cg06018296      R       NEK3    3'UTR
cg06018296      R       NEK3    3'UTR
cg06018296      R       NEK3    Body
cg05172994      F       WDR20   3'UTR
cg05172994      F       WDR20   3'UTR
cg05172994      F       WDR20   3'UTR
cg05172994      F       WDR20   Body

답변2

사용밀러( mlr):

sed 's/;/\t/' file | mlr --nidx --fs tab nest --evar ';' -f 4

먼저 각 줄의 첫 번째 줄을 탭으로 sed바꾸고 ;탭으로 구분된 세 번째 필드를 두 개의 개별 필드로 분할합니다. GNU는 sed이 명령을 사용하여 탭 문자를 삽입할 수 있지만 모든 구현이 가능한 것은 아닙니다. 그렇게 할 수 없으면 + 를 누르는 대신 리터럴 탭 문자를 입력하세요.\tssed\tCtrl+VTab

그런 다음 Miller는 탭으로 구분된 데이터( )를 읽고 쓰고 네 번째 탭으로 구분된 필드( )의 구분된 하위 필드를 기반으로 --nidx --fs tab각 레코드를 "폭발"(또는 "중첩 해제")합니다 .;nest --evar ';' -f 4

질문의 데이터 출력을 제공합니다.

cg13201342      F       ARNT    ARNT
cg13201342      F       ARNT    ARNT
cg13201342      F       ARNT    CTSK 3'UTR
cg13201342      F       ARNT    3'UTR
cg13201342      F       ARNT    3'UTR
cg13201342      F       ARNT    TSS1500
cg05269359      F       SCN4B   SCN4B
cg05269359      F       SCN4B   SCN4B
cg05269359      F       SCN4B   SCN4B 3'UTR
cg05269359      F       SCN4B   3'UTR
cg05269359      F       SCN4B   3'UTR
cg05269359      F       SCN4B   Body
cg06018296      R       NEK3    NEK3
cg06018296      R       NEK3    NEK3
cg06018296      R       NEK3    NEK3 3'UTR
cg06018296      R       NEK3    3'UTR
cg06018296      R       NEK3    3'UTR
cg06018296      R       NEK3    Body
cg05172994      F       WDR20   WDR20
cg05172994      F       WDR20   WDR20
cg05172994      F       WDR20   WDR20 3'UTR
cg05172994      F       WDR20   3'UTR
cg05172994      F       WDR20   3'UTR
cg05172994      F       WDR20   Body

이 작업은 uniq인접한 행에서 중복 항목을 제거합니다.


다음만 사용하세요 awk:

awk -F '\t' 'BEGIN { OFS=FS }
    {
        nf = split($3,a,";")
        for (i = 2; i <= nf; ++i) print $1, $2, a[1], a[i]
    }' file

이렇게 하면 세 번째 필드가 분할 ;되고 세 번째 필드의 두 번째 하위 필드에 대해 처음 두 필드와 원래 세 번째 필드의 첫 번째 하위 필드가 계속 출력됩니다.

그 출력은 이 답변의 상단에 있는 파이프의 출력과 동일합니다.

답변3

입력의 공백에 관계없이 POSIX awk를 사용하십시오.

$ awk -F'[[:space:];]+' -v OFS='\t' '{
    n=(NF-2)/2; for (i=1; i<=n; i++) print $1, $2, $(2+i), $(2+i+n)
}' file
cg13201342      F       ARNT    3'UTR
cg13201342      F       ARNT    3'UTR
cg13201342      F       ARNT    3'UTR
cg13201342      F       CTSK    TSS1500
cg05269359      F       SCN4B   3'UTR
cg05269359      F       SCN4B   3'UTR
cg05269359      F       SCN4B   3'UTR
cg05269359      F       SCN4B   Body
cg06018296      R       NEK3    3'UTR
cg06018296      R       NEK3    3'UTR
cg06018296      R       NEK3    3'UTR
cg06018296      R       NEK3    Body
cg05172994      F       WDR20   3'UTR
cg05172994      F       WDR20   3'UTR
cg05172994      F       WDR20   3'UTR
cg05172994      F       WDR20   Body

관련 정보