為什麼 awk 欄位分隔符號不能一致運作?

為什麼 awk 欄位分隔符號不能一致運作?

我正在嘗試使用 awk 和 ss 的輸出來列印第四列。有時它會起作用,但有時它會錯誤地合併或拆分列。我嘗試了幾種不同的 FS 選項,這裡有兩個或多個空格,因為欄位標題包含一個空格。

這給了我第五列和一個空白標題:

$ ss -tn
State   Recv-Q    Send-Q                Local Address:Port                   Peer Address:Port     
ESTAB   0         36                     172.31.19.34:22                   172.115.128.85:64478    
ESTAB   0         0             [::ffff:172.31.19.34]:80          [::ffff:172.115.128.85]:65446    


$ ss -tn | awk -F '[[:space:]][[:space:]]+' '{print $4}'

172.115.128.86:64478 
[::ffff:172.115.128.86]:65446 

這裡相同的命令給了我第四列,這就是我想要的。

$ ss -tn
State     Recv-Q      Send-Q              Local Address:Port               Peer Address:Port       
ESTAB     0           36                   172.31.19.34:22               172.115.128.85:64478   

$ ss -tn | awk -F '[[:space:]][[:space:]]+' '{print $4}'
Local Address:Port
172.31.19.34:22

我知道cut可能更容易,但我正在使用,awk因為我想做進一步的處理。

添加細節:我不確定為什麼 ss 顯示此 IPv6 樣式位址。這是從我的筆記型電腦到 apache 伺服器的連接,但我的筆記型電腦沒有 IPv6 位址。

答案1

作為穆魯暗示在一個評論awk可能會持續工作。可以變化的是 的輸出中的間距ss

結果ss -nt1輸出了七列,標題分別是:State, Recv-Q, Send-Q, Local Address, Port, Peer Address, Port。第四列和第五列之間以冒號 ( :) 分隔;第六和第七也是同樣的情況。所有其他內容均由空格字元分隔。
所有列都在需要對齊的地方填充了空格。第四個和第六個填充在其左側,所有其他填充在右側。

可能會發生進一步的填充:

  1. 如果 的輸出ss -nt定向到終端:

    1. 如果其行的最小長度(計算為每個字段的最長內容加上最小間距(六個字元)總和)小於終端的寬度,則每行透過均勻填充擴展到終端的寬度所有帶有空格的列;

    2. 否則,線會被打斷,並且欄位會跨線對齊(如上填充,直到終端的寬度)。

  2. 如果 的輸出ss -nt不定向到終端(例如,它透過管道傳輸或重定向到常規檔案),則行的實際長度定義為 80 的最小倍數,該倍數高於上面定義的最小長度。所有列均均勻地填入空格,以達到總行長度,即 80、160、240、...字元2

因此,不能保證兩列會被兩個或多個空格分隔,這使得該序列對於分割來說不可靠。

儘管如此,您仍然可以以相當安全的方式處理 的輸出ss -tn,注意列標題是已知且固定的,並且除了標題之外,其任何列都不應包含空格3

ss -nt | sed '
  1 s/[ ]Address:/_Address|/g           # Remove the known spaces from column
                                        # headers; also, change ":" into "|"
  s/:\([^:|]*[ ]\)/|\1/g                # Change the colons used as separators
                                        # into vertical bars "|", to avoid
  s/:\([^:|]*\)$/|\1/g                  # confusion with those in IPv6s
' | awk -v FS='\\||[ ]+' -v OFS=":" '   # Split on sequences of one or more
  { print $4,$5 }                       # spaces OR on any vertical bar
'

這將僅列印第四和第五列(本地位址和連接埠),以冒號分隔。請注意,使用不是預設的單一空格的欄位分隔符號awk將識別八列而不是七列,並且如果您執行 a { $1=$1; print; },它將OFS在最後一列右填充的任何行的末尾列印一個至少有一個空格。


1其他選項(例如-i, -e, -m)會大幅改變 的輸出ss。為了簡潔和清楚起見,我們將只專注於這個確切的命令。
2近似且可能不精確。但這與這個問題/答案的要點無關。
3顯然這並不能保證,我們故意不嘗試涵蓋所有不常見的情況。

答案2

為什麼 awk 欄位分隔符號不能一致運作?

是的,不可靠的是 的輸出中的空格數量ss

第四欄,這就是我想要的。

然後只需刪除標題 ( -H) 並選擇第四列:

$ ss -taH | awk '{print $4}'
172.31.19.34:22
[::ffff:172.31.19.34]:80

由於標頭是固定的,只需將其添加回來(如果需要):

$  echo "Local Address:Port"
Local Address:Port

完整命令:

$ echo "Local Address:Port"; ss -tnH | awk '{print $4}'
Local Address:Port
172.31.19.34:22
[::ffff:172.31.19.34]:80

是的,您的電腦始終具有 IPv6(一個或多個)位址。如果您不需要它們,只需詢問 IPv4 位址:

$ ss -tnH4 | awk '{print $4}'
172.31.19.34:22

相關內容