2012-07-07 3 views
2

다음은 12 열의 데이터에 유용하지만 전적으로 같지 않은 70 열 이상을 가지고 있으며 변환 된 모든 열을 과학적 값으로 대체해야합니다 .과학 표기법을 여러 필드에서 십진수로 변환

awk -F',' '{printf "%.41f\n", $12}' $file 

감사

이 한 라인 ..

이 아닌 변환 출력 작동

2012-07-01T21:59:50,2012-07-01T21:59:00,1817,22901,264,283,549,1,2012-06-24T13:20:00,2.600000000000000e+001,4.152327506554059e+001,-7.893523806678388e+001,5.447572631835938e+002,2.093000000000000e+003,5.295000000000000e+003,1,194733,1.647400093078613e+001,31047680,1152540,29895140,4738,1.586914062500000e+000,-1.150000000000000e+002,0.000000000000000e+000,0.000000000000000e+000,0.000000000000000e+000,0.000000000000000e+000,0.000000000000000e+000,0.000000000000000e+000,0.000000000000000e+000,3.606000000000000e+003,0.000000000000000e+000,0.000000000000000e+000,0.000000000000000e+000,4.557073364257813e+002,0.000000000000000e+000,0.000000000000000e+000,0.000000000000000e+000,11,0.000000000000000e+000,2.000000000000000e+000,0,0,0,0,4.466836981009692e-004,0.000000000000000e+000,0.000000000000000e+000,0.000000000000000e+000,8,0,840,1,600,1,6,1,1,1,5,2,2,2,1,1,1,1,4854347,0,- 

UPDATE. 어떤 이유로 if else 문을 삽입하는 데 약간의 문제가 있습니다. 모든 것이 파일이나 cli에서 구문 오류를 발생시키는 것 같습니다.

awk -F',' '{for (i=1;i<=NF;i++) {if (i <= 9||i == 16||i == 17||i == 19||i == 20||i == 21||i == 22|| i == 40|| i == 43||i == 44||i == 45||i == 46||i >= 51) printf ($i",")};}' $file 

위의 코드에 다음 문장을 삽입하고 싶습니다.

else if (i == 10) printf ("%.41f", $i) 

그것을 밖으로 일있어 해결했다. 모든 위대한 아이디어에 감사드립니다. awk -f를 사용하여 파일에서 작동하도록 만들 수는 없지만 커맨드 라인에서 이것은 훌륭하게 작동합니다. 내 프로그램에이 라이너 하나를 넣었습니다.

awk -F',' '{for (i=1;i<=NF;i++) {if (i <= 9||i == 16||i == 17||i >= 19&&i <= 22|| i == 40|| i >= 43&&i <= 46||i >= 51&&i <= 70) printf($i","); else if (i == 10||i == 18) printf("%.2f,", $i); else if (i == 11||i == 12) printf("%.41f,", $i); else if (i == 13) printf("%.1f,", $i); else if (i == 14||i == 15||i >= 24&&i <= 46) printf ("%d,", $i); else if (i == 23) printf("%.4f,", $i); else if (i >= 47&&i <= 50) printf("%.6f,", $i); if (i == 71) printf ($i"\n")};}' 

결과

2012-07-01T21:59:50,2012-07-01T21:59:00,1817,22901,264,283,549,1,2012-06-24T13:20:00,26.00,41.52327506554058800247730687260627746582031,-78.93523806678388154978165403008460998535156,544.8,2093,5295,1,194733,16.47,31047680,1152540,29895140,4738,1.5869,-115,0,0,0,0,0,0,0,3606,0,0,0,455,0,0,0,11,0,2,0,0,0,0,0.000447,0.000000,0.000000,0.000000,8,0,840,1,600,1,6,1,1,1,5,2,2,2,1,1,1,1,4854347,0,- 
+1

필자는 명령 줄에서이 작업을 수행하지 않을 것입니다. 아래의 @DennisWilliamson 접근법을 확인하고 싶을 것입니다. – Levon

답변

3

각 필드의 형식을 선택하는 루프에서 정규식 매칭을 수행 할 수 있습니다

#!/usr/bin/awk -f 
BEGIN { 
    d = "[[:digit:]]" 
    OFS = FS = "," 
} 
{ 
    delim = "" 
    for (i = 1; i <= NF; i++) { 
     if ($i ~ d "e+" d d d "$") { 
      printf "%s%.41f", delim, $i 
     } 
     else { 
      printf "%s%s", delim, $i 
     } 
     delim = OFS 
    } 
    printf "\n" 
} 

편집 :

내가 너무 이상 버전을 변경했습니다 파일에서 AWK 스크립트로 어떻게 사용되는지 확인할 수 있습니다. 저장하고 (나는 이것을 "scinote"라고 부름) 실행 파일로 설정하고 다음과 같이 실행하십시오 : ./scinote inputfile

또한 질문에 추가 한 최신 버전을 수정하여 조금만 만들었습니다. 더 간단하고 위와 같이 스크립트 파일에 들어갈 준비가되었습니다.

#!/usr/bin/awk -f 
BEGIN { 
    plainlist = "16 17 19 20 21 22 40 43 44 45 46" 
    split(plainlist, arr) 
    for (i in arr) { 
     plainfmt[arr[i]] = "%s" 
    } 
    OFS = FS = "," 
} 
{ 
    delim = "" 
    for (i = 1; i <= NF; i++) { 
     printf "%s", delim 
     if (i <= 9 || i in plainfmt || i >= 51) { 
      printf plainfmt[i], $i 
     } 
     else if (i == 10) { 
      printf "%.41f", $i 
     } 
     else if (i == 12) { 
      printf "%.12f", $i 
     } 
     delim = OFS 
    } 
    printf "\n" 
} 

다른 형식 (오히려 하나의 당에 비해) 더 많은 필드를 가지고 있다면, 당신은 plainfmt 배열과 비슷한 일을 할 수 있습니다.

+0

'cat $ file | awk -f ~/bin/so.awk awk : ./so.awk:16 :} awk : ./so.awk:16 :^구문 오류 ' Windows에서 cygwin을 사용 중입니다. 차. –

+0

@RoadKing :'BEGIN' 블록을 닫는 것을 잊었습니다. 내 편집 된 답변보기 –

+0

이제 정상적으로 작동합니다. 고마워요. –

0

당신 수 항상 데이터 필드의 모든을 반복하고 당신의 printf에 사용합니다. 간단한 파일이 바로 기계를 테스트하려면이 시도해 볼 수도 있습니다 : 필드가 whitepace에 의해 분할 될 수 있도록 -F가 여기에 설정되어 있지 않은지

awk '{for (i=1; i<=NF; i++) printf("%d = %s\n", i, $i);}' data.txt 

참고.

NF는 라인 필드 수의 사전 정의 된 변수, 필드 ($NF까지 예 $1, $2 등) (1) 시작한다. $0은 전체 행입니다.

은 그래서 예를 들어이 작동 할 수 있습니다

awk -F',' '{for (i=1; i<=NF; i++) printf "%.41f\n", $i}' $file 

업데이트 아래 코멘트 (안 시스템 테스트에 구문)에 따라 :

을 수행해야 특정 필드가있는 경우 다르게 처리해야하는 경우 다른 필드를 다르게 처리하려면 switch 문이나 if-statement을 사용해야 할 수 있습니다. 이것은 당신이 파일에 스크립트를 저장하는 경우의이 so.awk를 호출하게, 쉽게하고 이런 식으로 호출 것 :

awk -f so.awk $file 

이 라인을 따라 뭔가 포함 할 수 있습니다 귀하의 스크립트를

BEGIN{ FS=',' } 
{ for (i=1; i<=NF; i++) 
    { 
     if (i == 20 || i == 22|| i == 30) 
     printf(" .. ", $i) 
     else if (i == 13 || i == 24) 
     printf(" ....", $i) 
     etc. 
    } 
} 

당신은 과정의 수를 가능한 경우 모든 단일 필드를 나열하지 않아도되도록 if (i > 2) ... 또는 다른 범위를 사용하십시오.

이 if 문에 대한 대안으로 위에서 언급 한 switch 문을 참조하십시오. 숫자 문자열 AWK도 있기 때문에

+0

% d와 % s을 (를) 필요로하고 반전 한 소수점을 얻기 위해 이것을 변경했습니다. 그러나 일부 필드는 변환 될 필요가 없으므로 왜곡되고 일부는 변환됩니다. 필드에 너무 많은 십진수가 있습니다 .... awk -F ',' '{for (i = 1; i <= NF; i ++) printf ("% s = % .41f \ n", i, $ i);} ' –

+0

@RoadKing 내 답변에 더 많은 정보를 추가했습니다. helfpul이 되길 바랍니다. 문제에 대한 추가 정보가있는 경우 모든 사람이 모든 주석을 검토하지 않으며 코멘트의 형식이 매우 좋지 않기 때문에 원래 게시물을 업데이트하는 것이 가장 좋습니다 (코드 참조). – Levon

+0

'if' 문으로 인해 일부 필드가 두 번 또는 세 번 인쇄됩니다. 'printf'를'printf ("..", $ i)'로 변경하십시오. –

관련 문제