printf와 AWK를 사용하여 출력 형식을 올바르게 지정

printf와 AWK를 사용하여 출력 형식을 올바르게 지정

일부 출력 형식을 지정하기 위해 printf 및 awk를 사용하려고 합니다. 기본적으로 최종 형식은 다음과 같습니다(모든 탭이 구분되어 있음).

chr10   100000624       100000625       10:100000625_A_G
chr10   100000644       100000645       10:100000645_A_C
chr10   100002463       100002464       10:100002464_C_T
chr10   100003241       100003242       10:100003242_G_T
chr10   100003303       100003304       10:100003304_A_G
chr10   10000337        10000338        10:10000338_C_T
chr10   100003515       100003516       10:100003516_A_G
chr10   100003784       100003785       10:100003785_C_T
chr10   100004359       100004360       10:100004360_A_G
chr10   100004440       100004441       10:100004441_C_G 
...

시작 파일은 다음과 같습니다(다른 열은 중요하지 않음).

10:100000625_A_G        G       A
10:100000645_A_C        C       A
10:100002464_C_T        C       T
10:100003242_G_T        G       T
10:100003304_A_G        G       A
10:10000338_C_T T       C
10:100003516_A_G        A       G
10:100003785_C_T        C       T
10:100004360_A_G        A       G
10:100004441_C_G        C       G ...
...

두 번째 열은 첫 번째 열보다 한 열 작아야 합니다. 원본 파일을 사용하여 기본적으로 다음을 수행했습니다.

awk -F ":" '$1=$1' OFS="\t" <(zcat <filename>) | awk -F "_" '$2=$2' OFS="\t" | awk -v OFMT="%f" 'BEGIN {OFS=FS="\t"} {print "chr"$1, $2-1, $2, $1":"$2"_"$3"_"$4}'


먼저 ID의 시작 부분을 ":"으로 분해한 다음 "_"로 분해했습니다. awk -F "[:_]"...두 구분 기호를 모두 사용하여 첫 번째 열을 나눌 수도 있지만 결국에는 차이가 없을 것이라고 생각합니다.

숫자가 과학적 표기법(12000000과 같은 숫자)으로 보고되는 몇 가지 경우를 제외하고는 작동하지만 이는 내가 원하지 않습니다. printf를 사용하면 과학적 표기법을 취소할 수 있어야 하는데 작동할 수 없습니다.

내 첫 번째 생각은 첫 번째와 네 번째 열을 문자열로, 두 번째와 세 번째 열을 소수점 없는 부동 소수점 숫자로 원한다는 것이었습니다. 그래서 다음을 시도했습니다 awk '{printf "%s\t%4.0f\t%4.0f\t%s\n" "chr"$1, $2-1, $2, $1":"$2"_"$3"_"$4}'. 그러나 다음과 같은 오류 메시지가 나타납니다.


awk: (FILENAME=- FNR=1) fatal: not enough arguments to satisfy format string
        `%s     %4.0f   %4.0f   %s
chr10'
                        ^ ran out for this one

형식 문자열이 내 파일의 필드 수에 비해 너무 긴 것 같지만 이유는 확실하지 않습니다. printf를 사용하다가 한 가지 기능을 발견했습니다. 이렇게 하면 awk '{printf "\t%s\t%4.0f\t%4.0f\t\n" "chr"$1, $2-1, $2, $1":"$2"_"$3"_"$4}'다음과 같은 결과를 얻습니다.

        100000624       100000625         10
chr10   100000644       100000645         10
chr10   100002463       100002464         10
chr10   100003241       100003242         10
chr10   100003303       100003304         10
chr10   10000337        10000338          10
chr10   100003515       100003516         10
chr10   100003784       100003785         10
chr10   100004359       100004360         10
chr10   100004440       100004441         10
chr10 

따라서 첫 번째 열은 다른 모든 열에 비해 한 행 아래로 밀려나고 네 번째 열은 잘립니다. 답장에서 printf 구문이 어떻게 작동하는지 설명해 주시면 정말 감사하겠습니다. 매우 감사합니다!

답변1

형식 문자열 뒤에 쉼표가 누락되었습니다.

awk -F'[:_\t]' '{ printf "%s\t%4.0f\t%4.0f\t%s\n", "chr"$1, $2-1, $2, $1":"$2"_"$3"_"$4 }' file
#                                                ^
#                                                |
#                                                this one

답변2

문제를 전혀 재현할 수는 없지만 문제가 있다고 가정하면 도움이 될 수 있습니다.

$ cat tst.awk
BEGIN { OFS="\t"; OFMT="%d" }
{
    split($1,f,/[:_]/)
    print "chr"f[1], f[2]-1, f[2], $1
}

$ awk -f tst.awk file
chr10   100000624       100000625       10:100000625_A_G
chr10   100000644       100000645       10:100000645_A_C
chr10   100002463       100002464       10:100002464_C_T
chr10   100003241       100003242       10:100003242_G_T
chr10   100003303       100003304       10:100003304_A_G
chr10   10000337        10000338        10:10000338_C_T
chr10   100003515       100003516       10:100003516_A_G
chr10   100003784       100003785       10:100003785_C_T
chr10   100004359       100004360       10:100004360_A_G
chr10   100004440       100004441       10:100004441_C_G

%d형식이 원하는 대로 작동하지 않지만 %4.0f작동 OFMT="%d"한다면 OFMT="%4.0f".

첫 번째 열이 아래로 밀리고 네 번째 열이 잘린다고 언급한 내용은 아마도 입력에 DOS 줄 끝이 있다는 의미일 것입니다.https://stackoverflow.com/questions/45772525/why-does-my-tool-output-overwrite-itself-and-how-do-i-fix-it.

답변3

사용유틸리티를 사용하면 다음과 같이 할 수 있습니다.

printf -v fmt '%s\t' '%s' '%4.0f' '%4.0f' '%s\n'
awk -F '\t' -v fmt="${fmt%?}" '
{
  split($1, a, /[:_]/)
  f1 = "chr" a[1]
  f2 = (f3 = a[2])-1
  f4 = sprintf("%4.0f", f3)
  sub(/:[^_]+/, ":"f4, $1)
  printf fmt, f1, f2, f3, $1
}
' file

관련 정보