Linux

AWK 在提取特定字元串時連接輸出行

  • December 22, 2019

給定針對子網的 nmap 輸出

Nmap scan report for 192.168.1.20
Host is up (0.010s latency).
MAC Address: EC:13:B2:E2:20:48 (Netonix)
Nmap scan report for 192.168.1.21
Host is up (0.010s latency).
MAC Address: EC:13:B2:E2:13:68 (Netonix)
Nmap scan report for 192.168.1.23
Host is up (0.010s latency).
MAC Address: EC:13:B2:E1:AE:A8 (Netonix)
Nmap scan report for 192.168.1.99
Host is up (0.00076s latency).
MAC Address: 90:6C:AC:48:86:DA (Fortinet)

目標是獲取 csv 或任何其他分隔格式的輸出:

IP,MAC,RTT
192.168.1.20,EC:13:B2:E2:20:48,0.010s
192.168.1.21,EC:13:B2:E2:13:68,0.010s
...

以上已使用 AWK 分兩步完成

$time_date=$(date "+%Y-%m-%d_%T")    # Get the immediate date and time
$nmap_command=$(nmap -sP 192.168.1.0/24 -n --max-rtt-timeout 50ms)

# Concatenate all lines including and between the patterns "Nmap scan report for"
c_list=$((awk '/Starting|done:/ {next} /Nmap scan report for/{ if (x) print x; x=""; }{ x=(!x)?$0:x" "$0; }END{ print x; }')<<<$nmap_command)

# Extract the values of interest from each line, add a header line, then add delimiter for every value extracted
list=$((awk -v OFS=',' -v date=$time_date 'BEGIN{ print "Date,IP,MAC,RTT" };{ gsub(/[()]/,""); for (I=1;I<=NF;I++) if ($I == "for") ip=$(I+1); else if ($I == "up") lat=$(I+1); else if ($I == "Address:") mac=$(I+1); } { print date, ip, mac, lat }')<<<$c_list)

printf '%s\n' "$list" > ~/Desktop/list.csv  # Send output to file

exit 0

問題是 上述兩步 awk 過程是否可以合併為一個 awk 命令。感謝您事先的所有輸入

EDIT 嘗試通過一些變體來鞏固這兩個步驟

x_list=$((awk '/Starting|done:/ {next} /Nmap scan report for/{ if (x) print x; x=""; }{ x=(!x)?$0:x" "$0; }END I=x BEGIN{ print "Date,IP,MAC,RTT" };{ gsub(/[()]/,""); for (I=1;I<=NF;I++) if ($I == "for") ip=$(I+1); else if ($I == "up") lat=$(I+1); else if ($I == "Address:") mac=$(I+1); } { print date, ip, mac, lat }')<<<$list_ips)

沒有希望。AWK 總是會給出一個很好的理由,為什麼要在 END 和 BEGIN 之間的間隙處停止處理。該練習實際上是嘗試創建一個 (bash) 函式,該函式能夠渲染任何重複模式的數據,nmap 輸出只是一個範例。

正常的做法是將所有行所需的資訊儲存到 awk 變數中,然後在塊的最後一行列印出數據。所以對於這個例子,你會有這樣的東西(我沒有編碼主機延遲情況,因為範例數據沒有顯示它)。

nmap -sP 192.168.1.0/24 -n --max-rtt-timeout 50ms |
 awk '/Nmap scan report for / {ip=$5}
      /Host is up/ { latency=$4 ; sub(/(/,"",latency) }
      /MAC Address: / { mac=$3; print(ip "," mac "," latency) ; ip=mac=latency="unknown" }
      BEGIN { print "IP,MAC,RTT"}

可能需要也可能不需要清除塊最後一行中的變數,具體取決於數據是否始終完整。如果有很多變數,請考慮使用數組而不是標量變數,例如ip, maclatency因為這些都可以通過一次刪除來清除。

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