Bash

使用 shell 腳本操作文本:如何填寫“缺失”行?

  • January 31, 2022

我有一個數據列表,例如 CSV,但有些行缺少值。我想根據使用 linux shell 腳本之前和之後的行為缺少的行生成一個值。

以這張桌子為例。

我想做的是用“Cindy:Ed”(B列中每個方向上最近的有效數據與“:”分隔符的連接)和“#”填寫第4行的“*” 48(47 和 49 的平均值,C 列每個方向上最近的有效數據點)。

輸出:

我的數據被格式化為任意行數的空格分隔文本文件。所有行都是三列。

雖然我知道 For 循環和 grep 等的方法,但我不知道如何在 vanilla linux shell 腳本中處理這個問題。

我的猜測是進行初始傳遞以查找具有星號和雜湊的行。然後進行第二遍,分別用 (awk ‘{print $2}’):(awk ‘{print $2}’) 之前和之後的行替換星號。

如果失去的數據在第一行或最後一行,我很樂意保持原樣。如果失去的數據在連續的行上,我可以將所有失去的行設置為相同的“Cindy:Ed”和相同的平均值。如果我能設置 “Cindy:Ed:1” 和 Cindy:Ed:2" 等就更酷了。

最壞情況原始輸入的準確範例:(它是一個跟踪路由,添加了“#”表示缺少的延遲)


1 192.168.200.2 1
2 192.168.200.1 1
3 10.10.10.1 1
4 11.22.33.44 2
5 11.22.33.55 5
6 * #
7 11.22.44.66 9
8 * #
9 * #
10 8.8.8.0 25
11 * #
12 * #
13 * #

我想要什麼:

1 192.168.200.2 1
2 192.168.200.1 1
3 10.10.10.1 1
4 11.22.33.44 2
5 11.22.33.55 5
6 11.22.33.55:11.22.44.66 7
7 11.22.44.66 9
8 11.22.44.66:8.8.8.0 17
9 11.22.44.66:8.8.8.0 17
10 8.8.8.0 25
11 * #
12 * #
13 * #

awk

#if a previous line with proper IP has been read
oldip != "" {
#i is counter for consecutive invalid lines
   i=0
#if IP is set, just print and go to next record
   if ($2!="*") {
       print ; oldip=$2 ; oldlat=$3 ; next
   }
#otherwise get following line and increase counter
   else {
#getline exit status => fails for the last line
       while (getline > 0) {i++
#check if new line has IP, if so
#set IPold:IPnew and average latency value
           if ($2!="*") {
               ipfill=oldip":"$2 ; latfill=(oldlat+$3)/2
#print filler lines for all consecutive records without value
               for (j=1 ; j<=i ; j++) {
                   print NR-i+j-1,ipfill,latfill
#alternative printing with oldIP:newIP:counter
#                   print NR-i+j-1,ipfill":"j,latfill
               }
#save current IP+lat and print "good" line
               oldp=$2; oldlat=$3
               print ; next
           }
       }
   }
#in case getline failed => all previous lines had no value
#just fill them with N/A data as in input
   for (j=0 ; j<=i ; j++) {
       print NR-i+j,"*","#"
   }
}

#If leading lines have no IP value, print them until IP is found
oldip == "" { if ($2=="*") {print ; next} ; oldip=$2 ; oldlat=$3 ; print }

輸入:

1 * #
2 * #
3 10.10.10.1 1
4 11.22.33.44 2
5 11.22.33.55 5
6 * #
7 11.22.44.66 10
8 * #
9 * #
10 8.8.8.0 25
11 * #
12 * #
13 * #

輸出:

1 * #
2 * #
3 10.10.10.1 1
4 11.22.33.44 2
5 11.22.33.55 5
6 11.22.33.55:11.22.44.66 7.5
7 11.22.44.66 10
8 11.22.33.55:8.8.8.0 17.5
9 11.22.33.55:8.8.8.0 17.5
10 8.8.8.0 25
11 * #
12 * #
13 * #

計算行的帶有計數器的替代輸出:

1 * #
2 * #
3 10.10.10.1 1
4 11.22.33.44 2
5 11.22.33.55 5
6 11.22.33.55:11.22.44.66:1 7.5
7 11.22.44.66 10
8 11.22.33.55:8.8.8.0:1 17.5
9 11.22.33.55:8.8.8.0:2 17.5
10 8.8.8.0 25
11 * #
12 * #
13 * #

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