Bash

文件頭尾不同條件行的平均值

  • January 31, 2022

編輯:為清晰起見對其進行了編輯,並使範例文件最小化且更具可重複性,以便於幫助。謝謝!

我有超過 1000 行的文件。每個文件都使用相同數量的行進行格式化。的格式有 3 個“標題行”,1000+ 行值(正負數,後有 6 個小數位),然後是 13 個“尾行”。行的格式可以在下面看到。在我的真實文件中,在某些行上,我想要不同的命令,例如從行中列印文本,對實際數據取平均值,複製文本的行和數據的平均值以及日期和時間的平均值。

這是一個大綱或各種長文件,其中包含關於每行目標的一些註釋。

下面的大綱是一個 dbriavated 範例。包含數據的行(範例中的第 4-9 行)實際上是真實文件中的第 4-1436 行。那麼大綱中的第 10 行就是實際文件中的第 1437 行。(希望這是有道理的)。數據線可以包含負數或正數,範圍從 -100 到 +5000。

ABCDEFGH               # Line 1... print text into output file (same on across all files)
1                      # Line 2... Take average of values across all the files in this line
2048                   # Line 3... Take average of values across all the files in this line
8.123456               # Line 4... Take average of values across all the files in this line (could be positive or negative)
5.123456               # Line 5... Take average of values across all the files in this line (could be positive or negative)
5.654321               # Line 6... Take average of values across all the files in this line (could be positive or negative)
4.654321               # Line 7... Take average of values across all the files in this line (could be positive or negative)
9.654321               # Line 8... Take average of values across all the files in this line (could be positive or negative)
1.654321               # Line 9... Take average of values across all the files in this line (could be positive or negative)
90.00                  # Line 10... Check and make sure value in this line across print if same
Sprite                 # Line 11... check and see if text is same across all values and print if same
cats10                 # Line 12... check and see if text is same across all values and print if same
07/02/20               # Line 13... See below for explantion on next 3 lines
08:32                  # Line 14...
08:32                  # Line 15...
290.000000             # Line 16... average across all files on this line
10.750000              # Line 17... average across all files on this line
SCANS23                # Line 18... output should be SCANS "average of values"
INT_TIME57500          # Line 19... output should be INT_TIME "sum of values"
SITE northpole         # Line 20...Check if all lines are same if so print line
LONGITUDE -147.850037  # Line 21... Output should be LONGITUDE "average"
LATITUDE 64.859375     # Line 22... Output should be LONGITUDE "average"

第 13 行是數據的來源日期,第 14 行是開始時間和結束時間。可能使用某種日期到十進制命令..有沒有辦法取日期的平均值?如果一個數據是在 2020 年 7 月 2 日獲取的,而另一個數據是在 2018 年 7 月 2 日獲取的,那麼輸出可以是 19 年 7 月 2 日嗎?時間的平均值也會被考慮在內。

我認為一些擴展的三元運算符可能是一條路徑,但是使用這麼多不同的情況根本不起作用。

awk -F: '
 FNR==1     { c++ };
 /^LATITUDE/    { a[FNR] += $6 };
 /^LONGITUDE/    { a[FNR] += $5 };
 /^SITE/    { a[FNR] += $4 };
 /^INT_TIME/    { a[FNR] += $3 };
 /^SCANS/    { a[FNR] += $2 };
 /^[+-]?([0-9]*[.])?[0-9]+$/ { a[FNR] += $1 };

 END {
   for (i in a) {
     printf (i==22 ? "LATITUDE%f": 
             i==21 ? "LONGITUDE%2.3f": 
             i==20 ? "SITE%2.3f": 
             i==19 ? "INT_TIME%2.3f": 
             i==18 ? "SCANS%2.3f": "%f") "\n", a[i] / c 
   }
 }' /home/test/test1.* > /home/average

假定所有範例文件都在其中,/home/test/aaaaaa-bbbb-cc10dddd-L1-2020070119*-01.std並希望“平均”文件輸出/home/dir/aaaaaa-bbbb-cc10dddd-L1-2020070119-01.std格式為 /aaaaaa-bbbb-cc10-dddd-L1-“year"“month"“day"“hour”-“elevation number “.std

輸入文件於 2020 年 1 月 7 日 19 小時在海拔 1 處拍攝:

/home/dir/dir2/aaaaaa-bbbb-cc10dddd-L1-202007011918-01.std
/home/dir/dir2/aaaaaa-bbbb-cc10dddd-L1-202007011929-01.std
/home/dir/dir2/aaaaaa-bbbb-cc10dddd-L1-202007011941-01.std
/home/dir/dir2/aaaaaa-bbbb-cc10dddd-L1-202007011953-01.std

輸出文件將是

/home/dir/aaaaaa-bbbb-cc10dddd-L1-2020070119-01.std

/home/dir/dir2/aaaaaa-bbbb-cc10dddd-L1-202007011918-01.std

ABCDEFGH
1
2048
-3.249389
-4.544701
5.822962
2.372011
-17.937092
20.000408
5.00
Sprite
cats10
07/01/20
19:18
19:18
290.000000
10.690000
SCANS23
INT_TIME57500
SITE northpole
LONGITUDE -147.850037
LATITUDE 64.859375

/home/dir/dir2/aaaaaa-bbbb-cc10dddd-L1-202007011929-01.std

ABCDEFGH
1
2048
-6.369022
-4.957337
-2.715081
1.766033
-20.002853
21.522350
5.00
Avantes
buoy10
07/01/20
19:29
19:29
290.000000
10.310000
SCANS23
INT_TIME57500
SITE giroof
LONGITUDE -147.850037
LATITUDE 64.859375

/home/dir/dir2/aaaaaa-bbbb-cc10dddd-L1-202007011926-01.std

ABCDEFGH
1
2048
2.961413
-14.236549
19.784035
2.711583
-18.305300
9.369226
5.00
Avantes
buoy10
07/02/20
19:26
19:26
290.000000
10.310000
SCANS23
INT_TIME57500
SITE giroof
LONGITUDE -147.850037
LATITUDE 64.859375

這可能接近您需要的,將paste(希望不是太多)輸入文件放入awk,關閉任何locale影響:

paste file[1-3] | LC_ALL=C awk -v"LNCT=$(wc -l <file1)" '

function avg(  sum)     {for (i=1; i<=NF; i++) sum += $i
                        return sum/NF
                       }

function same()         {for (i=2; i<=NF; i++) if ($1 != $i) return 0
                        return 1
                       }

NR == 1                 {print $1
                        next
                       }
NR <= (LNCT-13) ||
NR >= (LNCT-6)  &&
NR <= (LNCT-5)          {print avg()
                        next
                       }

NR >  (LNCT-13) &&
NR <= (LNCT-10)         {print (same()?$1:"") 
                       }
NR >= (LNCT-9) &&
NR <= (LNCT-7)          {if (NR == (LNCT-9))    FMT = "%m/%d/%y"
                          else                 FMT = "%H:%M"

                        for (i=1; i<=NF; i++)  {CMD = "date +%s -d\"" $i"\""
                                                CMD | getline  $i
                                                close (CMD)
                                               }
                        CMD = "date +" FMT " -d\"@" avg() "\""
                        CMD | getline ITEM
                        close (CMD)
                        print ITEM
                       }

                       {ITEM = $1
                        gsub (/[0-9]*/, "", ITEM)
                        if (gsub (/SCANS|INT_TIME|LONGITUDE|LATITUDE/, ""))    {print ITEM, avg()
                                                                               }
                        if (gsub (/SITE/, ""))         print ITEM, (same()?$1:"") 
                       }
'
ABCDEFGH
1
2048
-2.219
-7.91286
7.63064
2.28321
-18.7484
16.964
5.00


07/01/20
19:24
19:24
290
10.4367
SCANS 23
INT_TIME 57500
SITE 
LONGITUDE -147.85
LATITUDE 64.8594

這有點笨拙,因為它通過行號檢測“特殊處理”行,尤其是。日期/時間,但它似乎做了所要求的。我們需要預先計算行數並通過變數傳遞wc - l輸出,awk假設所有文件都具有相同的長度。可能還有其他/更好的方法。對於日期/時間計算:對於每次發生的事件都執行一個外部命令,這非常耗費資源date,最重要的是,並非在所有作業系統版本上都可用。它適用於我的 linux 系統,但我願意接受更好的想法。

引用自:https://unix.stackexchange.com/questions/688437