2012-07-07 99 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

這是工作的非轉換的輸出。由於某些原因,我插入else if語句時遇到了一些問題。似乎一切都給了我一個文件或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 2012-07-07 19:31:50

回答

3

你可以做正則表達式匹配在一個循環中,選擇每個字段的格式,因爲數字也是字符串AWK:

#!/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」),並將其設置爲可執行chmod u+x 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,如果這使得區別。 – 2012-07-07 19:46:40

+0

@RoadKing:我忘了關閉'BEGIN'塊。看到我編輯的答案。 – 2012-07-07 20:18:57

+0

好吧,現在就開始工作。非常感謝 – 2012-07-07 20:36:05

0

你總是可以通過你所有的數據字段的循環,並在您的printf使用它們。對於一個簡單的文件只是爲了測試的機制,你可以試試這個:

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

注意-F此處未設置,那麼域將whitepace進行分割。

NF是一行上字段數量的預定義變量,字段以1開頭(例如,$1,$2等,直到$NF)。 $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語句。

+0

我改變它爲了得到我需要的所有小數點,並且反轉了%d和%s,但是有些字段不需要轉換,所以它們變得扭曲了,字段中的小數點太多.... awk -F',''{for(i = 1; i <= NF; i ++)printf(「%s =%.41f \ n」,i,$ i);} ' – 2012-07-07 17:53:17

+0

@RoadKing我給我的答案增加了一些信息 - 希望這是helfpul。如果您有關於該問題的更多信息,最好更新原始帖子,因爲不是所有人都會查看所有評論,而且評論中的格式不太好(請參閱代碼)。 – Levon 2012-07-07 18:06:37

+0

您的if語句會導致某些字段被打印兩次或三次。將'printf'改爲'printf(「..」,$ i)'。 – 2012-07-07 19:21:22