我有一个bash脚本,它生成一个表作为输出,如下所示:
Name IP Address IPv6 Address Address Source Connection Type
Inferno 192.168.0.12 N/A DHCP Ethernet
VirgilioMarone 192.168.0.10 N/A DHCP Ethernet
RE305 192.168.0.2 N/A DHCP Wi-Fi
Google-Nest-Hub 192.168.0.100 N/A DHCP Wi-Fi
iPaddiG 192.168.0.216 N/A DHCP Wi-Fi
* N/A DHCP Wi-Fi
Alighieri 192.168.0.13 N/A DHCP Wi-FI
我需要确定一个算法,该算法接收上表并将"-“放在字段为null的地方,如下所示(我不会复制其他行,只是为了简化文本):
Name IP Address IPv6 Address Address Source Connection Type
* - N/A DHCP Wi-Fi 5GHz
附注:文本之间没有制表符;只有空格。
发布于 2020-12-12 04:27:48
我将使用第一行来获取每列的预期大小。
head -1 /path/to/file |
grep -oE '[^ ]([^ ]| [^ ])* * ' |
awk '{print length($0)}'
head -1
保留第一行onlygrep -oE '[^ ]([^ ]| [^ ])* * '
捕获所有以非空格字符[^ ]
开头的字符串,后跟不包含两个连续空格的空格序列([^ ]| [^ ])*
,并以至少包含两个空格的空格序列结束*
;注意正则表达式中的确切字符,否则它将不会执行,而只是显示每个序列的长度
请注意,缺少最后一列,因为它不是以2+空格结尾。这是一件好事,因为我假设最后一列不应该被限制为固定的宽度。
对于您的示例,它输出:
21
18
33
17
一旦你有了这个列表,你就可以将它存储到一个数组中,例如:
mapfile -t widths < <(head -1 /path/to/file |
grep -oE '[^ ]([^ ]| [^ ])* * ' |
awk '{print length($0)}')
然后,您可以读取每一行,并使用每列的固定宽度将其拆分:
while IFS= read -r line || [[ -n "$line" ]]; do
t=0;
for x in "${widths[@]}"; do
s=${line:$t:$x};
if [[ "$s" =~ ^\ *$ ]]; then
printf %s "${s/ /-}";
else
printf -- %s "$s";
fi;
((t+=x));
done;
s=${line:$t};
if [ -z "$s" ]; then
printf -- -\\n;
else
if [[ "$s" =~ ^\ *$ ]]; then
printf %s\\n "${s/ /-}";
else
printf -- %s\\n "$s";
fi;
fi;
done < /path/to/file
while IFS= read -r line || [[ -n "$line" ]]; do ... done < /path/to/file
读取$line
变量中的每一行;使用-r
选项读取以便不解释转义序列,并设置IFS=
以便不修剪前导和尾随空格,这一点非常重要;|| [[ -n "$line" ]]
奖励是一个技巧,它修复了read
的限制,如果文件的最后一行不以换行符结束,则返回false。charactert
是到目前为止在linefor x in "${widths[@]}"; do ... done
循环中通过widths
数组读取的字符总数计算得到的t
从索引t+x
中提取字符,换句话说,它从行中提取一列,保留尾随空格字符,这就是魔术发生的地方。因为一旦有了它,你就需要wonif [[ "$s" =~ ^\ *$ ]]; then printf %s "${s/ /-}"; else printf -- %s "$s"; fi;
检查列是否完全为空,在这种情况下,它调用printf %s "${s/ /-}"
输出第一个字符被连字符替换的字符串,同时保持字段宽度不变(你可以对printf -- "%-${x}s" -
做同样的事情),否则它会按printf -- %s "$s"
打印字符串,请确保使用--
,否则,如果字符串"$s"
以hypen((t+=x))
开头,将变量t
推进到下一列,以便下一列从正确的索引s=${line:$t}
获取从索引t
开始直到行尾的最后一列,即如果没有固定宽度的\\n
结束输出,以便输出换行符如果一切顺利,它应该会显示:
Name IP Address IPv6 Address Address Source Connection Type
Inferno 192.168.0.12 N/A DHCP Ethernet
VirgilioMarone 192.168.0.10 N/A DHCP Ethernet
RE305 192.168.0.2 N/A DHCP Wi-Fi
Google-Nest-Hub 192.168.0.100 N/A DHCP Wi-Fi
iPaddiG 192.168.0.216 N/A DHCP Wi-Fi
* - N/A DHCP Wi-Fi
Alighieri 192.168.0.13 N/A DHCP Wi-FI
https://stackoverflow.com/questions/65242985
复制相似问题