Linux
AWK 在提取特定字元串時連接輸出行
給定針對子網的 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
,mac
,latency
因為這些都可以通過一次刪除來清除。