May*_*y11 6 macos bash awk sed
我试图从命令输出中选择特定的列(2 和 3),其中列分隔符也出现在文本中。考虑这个示例文本(输出的虚构部分nmcli
):
SSID BSSID RSSI CHANNEL
Something 12:34:56:78:98:ab -10 1
Something guest a2:34:56:78:98:ab -10 2
Network b2:34:56:78:98:ab -20 3
Public network c2:34:56:78:98:ab -30 4
Run Code Online (Sandbox Code Playgroud)
列由单个空格分隔,但 SSID 中也有单个空格。如果没有这些,使用cut
.
在 GNU 中,我以某种方式使用 下划线替换 SSID 中的空格来sed
使其工作:\w\s\w
sed -e 's/\w\s\w/_/g'
Run Code Online (Sandbox Code Playgroud)
但这在 Mac 上不起作用。所以我的第二个最好的想法是按职位划分。是否有可能:
有更聪明的方法吗?SSID 中的那些空格也会让 awk 感到困惑,所以
awk '{print $2 " " $3}'
Run Code Online (Sandbox Code Playgroud)
在这些行中不起作用。
--- 编辑 --- 问题是,当使用 MacOS airport -s 生成的数据时,最后一个字段也有空格,所以我也不能从后面走:
SSID BSSID RSSI CHANNEL HT CC SECURITY (auth/unicast/group)
AA1 d8:12:b6:b8:10:d5 -92 9 Y -- WPA(PSK/AES/AES) RSN(PSK/AES/AES)
XXXXX Guest ba:11:e4:4a:01:71 -90 6 Y -- RSN(PSK/AES/AES)
Netwrrk 5a:99:68:b7:0d:ca -89 36 Y DE RSN(PSK/AES/AES)
T-3_7edb87 64:11:ea:7e:db:87 -87 11 Y -- WPA(PSK/AES,TKIP/TKIP) RSN(PSK/AES,TKIP/TKIP)
abcde 58:22:8f:c6:7c:de -86 6 Y -- RSN(PSK/AES/AES)
abcde 64:66:88:3f:b2:9a -78 8 Y -- RSN(PSK/AES,TKIP/TKIP)
ababa 74:ac:77:b1:e3:59 -74 6 Y -- RSN(PSK/AES/AES)
Run Code Online (Sandbox Code Playgroud)
对两个问题合二为一表示歉意;谢谢你们!
以下内容已使用 GNU和macOS 附带的awk
BSD进行了测试(但正如评论所述,它应该适用于任何 POSIX ):awk
Ed
awk
$ awk 'NR==1 {n = match($0, /[[:space:]]BSSID[[:space:]]/) + 1}
NR>1 {$0 = substr($0, n); print $1, $2}' file.txt
12:34:56:78:98:ab -10
a2:34:56:78:98:ab -10
b2:34:56:78:98:ab -20
c2:34:56:78:98:ab -30
Run Code Online (Sandbox Code Playgroud)
BSSID
第一个块仅适用于第一行并存储in 变量的索引n
。第二块适用于所有其他行。它通过抑制n-1
第一个字符来修改它们,并打印新的第一个和第二个字段。
只是为了好玩(因为它有点复杂),这里还有一个sed
基于解析标题行的相同想法的解决方案,并使用 GNU和macOS 附带的sed
BSD进行了测试。sed
$ sed -En '
1 {
s/^(.*[[:space:]])BSSID[[:space:]].*/\1/
h
}
2,$ {
G
:a
s/.(.*\n.*)./\1/
ta
s/^([^[:space:]]+[[:space:]]+[^[:space:]]+).*/\1/
p
}' file.txt
12:34:56:78:98:ab -10
a2:34:56:78:98:ab -10
b2:34:56:78:98:ab -20
c2:34:56:78:98:ab -30
Run Code Online (Sandbox Code Playgroud)
我们使用扩展正则表达式 ( -E
) 并抑制默认回显 ( -n
)。
BSSID
我们首先删除从(替换命令)开始的第一行的末尾s/^(.*[[:space:]])BSSID[[:space:]].*/\1/
并将结果存储在保留空间(h
)中。在第一个示例中,保留空间现在包含(开始和结束标记为^
and $
):
^ SSID $
Run Code Online (Sandbox Code Playgroud)
除第一行 ( 2,$
) 之外的所有行均按如下方式修改并打印(最终p
):
添加换行符,后跟保留空格 ( G
)。示例的第二行变为:
^ Something 12:34:56:78:98:ab -10 1\n SSID $
Run Code Online (Sandbox Code Playgroud)
通过删除换行符后的第一个字符和最后一个字符来迭代(循环:a
... ta
),直到删除换行符后的所有字符(替换命令s/.(.*\n.*)./\1/
)。示例的第二行变为:
^12:34:56:78:98:ab -10 1\n$
Run Code Online (Sandbox Code Playgroud)
删除第二个空格字符串 ( ) 之后(包括)的所有内容s/^([^[:space:]]+[[:space:]]+[^[:space:]]+).*/\1/
。示例的第二行变为:
^12:34:56:78:98:ab -10$
Run Code Online (Sandbox Code Playgroud)
如果重要的话, GNUsed
版本更紧凑一些:
^ SSID $
Run Code Online (Sandbox Code Playgroud)
在每个 Unix 机器上的任何 shell 中使用任何 awk:
$ awk 'NR==1{ match($0,/BSSID.*RSSI/); next } { $0=substr($0,RSTART,RLENGTH); $1=$1; print }' file
d8:12:b6:b8:10:d5 -92
ba:11:e4:4a:01:71 -90
5a:99:68:b7:0d:ca -89
64:11:ea:7e:db:87 -87
58:22:8f:c6:7c:de -86
64:66:88:3f:b2:9a -78
74:ac:77:b1:e3:59 -74
Run Code Online (Sandbox Code Playgroud)
这里使用 GNU 怎么样grep
(在 RedHat 中测试),它将通过使用正则表达式来简单地捕获所需的字符串。仅使用所示示例进行编写和测试。
这是使用正则表达式的在线演示。
grep -oP '(?<=\s)[0-9a-f]{2}(:[0-9a-f]{2}){5}\s+-?[[:digit:]]{2}' Input_file
Run Code Online (Sandbox Code Playgroud)
或者尝试perl
以下(感谢@tripleee):
perl -nle 'm/(?<=\s)[0-9a-f]{2}(:[0-9a-f]{2}){5}\s+-?[[:digit:]]{2}/ and print "$&"' Input_file
Run Code Online (Sandbox Code Playgroud)