如何用awk正确移除配置行中含单引号空格的最后字段?
问题与解决方案
问题
我有一份配置文件,示例行如下:
set system login user alice full-name 'Alice Example' set system login user alice level admin
需要移除每行的最后字段。尝试用awk处理时遇到问题:
$ echo "set system login user alice full-name 'Alice Example'" | awk '{$NF=""; print}' set system login user alice full-name 'Alice
该命令对单引号包裹的含空格最后字段无效;修改字段分隔符后结果仍不对:
$ echo "set system login user alice full-name 'Alice Example'" | awk -F "[ ']" '{$NF=""; print}' set system login user alice full-name Alice Example
请问错误出在哪?如何得到仅保留set system login user alice full-name的正确结果?
完整配置示例
set firewall all-ping enable set firewall broadcast-ping disable set firewall group port-group WebServices0xFF port 8080 set firewall group port-group WebServices0xFF port 8081 set firewall group port-group WebServices0xFF port 9090 set firewall group port-group WebServices0xFF port 9091 set firewall group port-group WebServices0xFF port 2006 set firewall group port-group WebServices0xFF port 2007 set firewall group port-group WebServices0xFF port 8000 set firewall group port-group WebServices0xFF port 10443 set firewall ipv6-receive-redirects disable set firewall ipv6-src-route disable set firewall ip-src-route disable set firewall log-martians enable set firewall receive-redirects disable set firewall send-redirects enable set firewall source-validation disable set firewall syn-cookies enable set interfaces bridge br1 address 10.12.34.100/24 set interfaces bridge br1 aging 300 set interfaces bridge br1 bridged-conntrack disable set interfaces bridge br1 hello-time 2 set interfaces bridge br1 max-age 20 set interfaces bridge br1 priority 32768 set interfaces bridge br1 promiscuous disable set interfaces bridge br1 stp false set interfaces ethernet eth0 duplex auto set interfaces ethernet eth0 poe output off set interfaces ethernet eth0 speed auto set interfaces ethernet eth0 vif 1100 bridge-group bridge br1 set interfaces ethernet eth1 duplex auto set interfaces ethernet eth1 poe output 24v set interfaces ethernet eth1 speed auto set interfaces ethernet eth1 vif 1100 bridge-group bridge br1 set interfaces ethernet eth2 duplex auto set interfaces ethernet eth2 poe output 24v set interfaces ethernet eth2 speed auto set interfaces ethernet eth2 vif 1100 bridge-group bridge br1 set interfaces ethernet eth3 duplex auto set interfaces ethernet eth3 poe output 24v set interfaces ethernet eth3 speed auto set interfaces ethernet eth3 vif 1100 bridge-group bridge br1 set interfaces ethernet eth4 duplex auto set interfaces ethernet eth4 poe output 24v set interfaces ethernet eth4 speed auto set interfaces ethernet eth4 vif 1100 bridge-group bridge br1 set interfaces ethernet eth5 duplex auto set interfaces ethernet eth5 speed auto set interfaces ethernet eth5 vif 1100 bridge-group bridge br1 set interfaces loopback lo set interfaces switch switch0 mtu 1500 set interfaces wireguard wg0 mtu 1420 set interfaces wireguard wg0 peer 1syRMYD1jIVFMUMm5hF/j0MzjMQmuC5mlcT1VVugIkU= allowed-ips 172.27.0.0/24 set interfaces wireguard wg0 peer 1syRMYD1jIVFMUMm5hF/j0MzjMQmuC5mlcT1VVugIkU= allowed-ips 10.5.44.0/24 set interfaces wireguard wg0 peer 1syRMYD1jIVFMUMm5hF/j0MzjMQmuC5mlcT1VVugIkU= endpoint 'wireguard.example.org:51820' set interfaces wireguard wg0 peer 1syRMYD1jIVFMUMm5hF/j0MzjMQmuC5mlcT1VVugIkU= persistent-keepalive 25 set interfaces wireguard wg0 peer 1syRMYD1jIVFMUMm5hF/j0MzjMQmuC5mlcT1VVugIkU= preshared-key wQ*obfuscated*X9/mf*obfuscated*yYM1/qcQeRow= set interfaces wireguard wg0 private-key WG4ZY8OD*obfuscated*7mW*obfuscated*0+5qoZ28= set interfaces wireguard wg0 route-allowed-ips true set service gui http-port 81 set service gui https-port 10443 set service gui older-ciphers enable set service lldp interface all set service pppoe-server authentication local-users username test1gw1 password kh93BsG4 set service pppoe-server authentication local-users username test1gw1 static-ip 1.2.3.5 set service pppoe-server authentication mode local set service pppoe-server client-ip-pool start 0.0.0.0 set service pppoe-server client-ip-pool stop 0.0.0.100 set service pppoe-server dns-servers server-1 9.9.9.9 set service pppoe-server dns-servers server-2 1.1.1.1 set service pppoe-server interface eth0 set service pppoe-server local-ip 1.2.3.4 set service snmp community o-obfuscated-f authorization ro set service snmp contact someone@example.org set service snmp location '1234, Teststreet 1' set service ssh port 10 set service ssh protocol-version v2 set service unms disable set system analytics-handler send-analytics-report false set system crash-handler send-crash-report false set system domain-name sub.example.org set system host-name test-router set system login banner post-login '' set system login banner pre-login '' set system login user alice authentication encrypted-password '$5$4*obfuscated*A$2*obfuscated*Q/.S*obfuscated*0/v*obfuscated*A' set system login user alice authentication plaintext-password '' set system login user alice authentication public-keys openpgp key AAAAB3N*obfuscated* set system login user alice full-name 'Alice Example' set system login user alice level admin set system name-server 9.9.9.9 set system name-server '2001:4860:4860::8888' set system name-server '2001:4860:4860::8844' set system ntp server 0.ubnt.pool.ntp.org set system ntp server 1.ubnt.pool.ntp.org set system ntp server 2.ubnt.pool.ntp.org set system ntp server 3.ubnt.pool.ntp.org set system options reboot-on-panic true set system syslog global facility all level notice set system syslog global facility protocols level debug set system syslog host 10.5.44.205 facility all level err set system time-zone Europe/Vienna
错误原因
- 第一个awk命令用默认空格作为字段分隔符,会把
'Alice Example'拆成'Alice和Example'两个字段,设置$NF=""后只会移除Example',留下'Alice,结果不符合预期。 - 第二个awk命令用
[ ']作为分隔符,会把单引号和空格都当成字段分隔符,直接破坏了单引号包裹字段的结构,导致输出混乱。
解决方案
方法1:awk脚本(精准处理单引号)
这个脚本会跟踪单引号的状态,只把不在单引号内的最后一个空格作为字段分隔点,从而完整移除最后一个字段:
awk '{ in_quote = 0 last_space = 0 for (i=1; i<=length($0); i++) { c = substr($0, i, 1) if (c == "'"") { in_quote = !in_quote } if (!in_quote && c == " ") { last_space = i } } if (last_space > 0) { print substr($0, 1, last_space-1) } else { print $0 } }' 你的配置文件名.txt
方法2:sed正则表达式
用sed的扩展正则匹配,跳过单引号内的内容,直接移除最后一个字段:
sed -E "s/(([^']*'[^']*')*[^']*)[[:space:]]+[^[:space:]]*$/\1/" 你的配置文件名.txt
验证效果
- 处理
set system login user alice full-name 'Alice Example',输出set system login user alice full-name - 处理
set system name-server '2001:4860:4860::8888',输出set system name-server - 处理
set system login banner post-login '',输出set system login banner post-login - 处理
set interfaces loopback lo,输出set interfaces loopback
内容的提问来源于stack exchange,提问作者Christoph
相关产品推荐
相关产品推荐

