我想从 的输出中提取制造商名称、卡的固件版本和状态fcinfo hba-port
,如下所示:
root-#> fcinfo hba 端口 HBA 端口 WWN:10000000c96a53c5 操作系统设备名称:/dev/cfg/c2 制造商: Emulex ← 型号:LPe11000-M4 固件版本:2.82a4(Z3D2.82A4) ← FCode/BIOS 版本:启动:5.02a1 Fcode:1.50a9 序列号:VM73059524 驱动程序名称: emlxs 驱动程序版本:2.60k (2011.03.24.16.45) 类型:N 端口 状态:在线 ← 支持的速度:1Gb 2Gb 4Gb 当前速度:4Gb 节点WWN:20000000c96a53c5
我用下面的方法提取这三个字段awk
......
root-#> fcinfo hba-port | awk '/Manufacturer:/{m=$2}/Firmware Version:/{F=$3}/State/{print m, F, $2}'
Emulex 2.82a4 online
Emulex 2.82a4 online
Emulex 2.82a4 offline
Emulex 2.82a4 offline
Emulex 2.82a4 online
Emulex 2.82a4 online
我想以更用户友好的形式呈现输出;例如,像下面这样...
HBA_Manufacturer Firmware_Version State
--------------------------------------------
Emulex 2.82a4 online
Emulex 2.82a4 offline
Emulex 2.82a4 offline
...其中添加标题并与数据对齐。我怎样才能做到这一点?
请注意,我需要 Solaris 解决方案。 (许多适用于 Linux 的命令不适用于 Solaris。)
答案1
您可以在不使用命令的情况下使列column
完全在 内对齐awk
,方法是
# fcinfo hba-port | awk '
BEGIN{man[-1]="HBA_Manufacturer"
ver[-1]="Firmware_Version"
sta[-1]="State"
man[0]="----------------"
ver[0]="----------------"
sta[0]="-----"
i=1
}
/Manufacturer:/ {man[i]=$2}
/Firmware Version:/ {ver[i]=$3}
/State:/ {sta[i]=$2; i++}
END {
maxlen1 = maxlen2 = maxlen3 = 0
for (j=-1; j<i; j++) {
if (length(man[j]) > maxlen1) maxlen1 = length(man[j])
if (length(ver[j]) > maxlen2) maxlen2 = length(ver[j])
if (length(sta[j]) > maxlen3) maxlen3 = length(sta[j])
}
for (j=-1; j<i; j++) {
printf("%-*s %-*s %-*s\n", maxlen1, man[j],
maxlen2, ver[j],
maxlen3, sta[j])
}
}'
这将读取整个输入文本,并将数据(包括标题)存储在man
、ver
和sta
(制造商、版本和状态)数组中。列标题放置在[-1]
条目中,破折号(在标题和数据之间形成一条线)放置在[0]
条目中;这些成为输出的前两行(见下文)。实际数据从 开始[1]
。
当到达数据末尾时,它确定每列中数据的最大长度(包括标题),然后使用计算出的列宽度打印所有数据(来自数组)。
printf("%16s", "Emulex")
打印Emulex
(十个开头的空格,后跟六个字符的名称,总共 16 个字符)。printf("%-16s", "Emulex")
(注意-
) 打印Emulex
(六个字符的名称,后跟十个尾随空格,总共 16 个字符)。printf("%-*s", 16, "Emulex")
与 的作用相同printf("%-16s", "Emulex")
,只是它从参数列表中获取 ,16
而不是格式字符串。所以上面会产生类似的输出
HBA_Manufacturer Firmware_Version State ---------------- ---------------- ----- Emulex 2.82a4 online Emulex 2.82a4 online Emulex 2.82a4 offline Emulex 2.82a4 offline Emulex 2.82a4 online Emulex 2.82a4 online
如果您希望列之间有更多空间,请在
printf
格式中添加空格。例如,"%-*s %-*s %-*s\n"
会给您一些更接近您显示的示例输出的内容。您显示的示例输出在标题后面有一行连续的破折号。如上所示,我的命令只会在每个标题下给出一小行破折号。如果某些数据较长,这一点会变得更加明显:
HBA_Manufacturer Firmware_Version State ---------------- ---------------- ----- Emulex 2.82a4 online Emulex 2.82a4 online Some_other_manufacturer 2.82a4 offline Emulex 2.82a4 offline Emulex 2.82a4 online Emulex 2.82a4 online
如有必要,可以修复此问题。
- 如果您的输入数据很大,这可能会失败,因为
awk
可能会耗尽空间来容纳所有数据。 - 如果您有旧版本
awk
(例如,在 Solaris 上),这可能会失败并出现语法错误。如果发生这种情况,请尝试将printf
语句全部放在一行上,如下所示printf("%-*s %-*s %-*s\n", maxlen1, man[j], maxlen2, ver[j], maxlen3, sta[j])
答案2
如果您想要的每列宽度是预先确定的,awk
有printf
其工作原理与 C 语言非常相似;例如,如果您想要 20 个字符、15 个字符和 10 个字符的列(中间有 2 个空格):
(as in Q) /State/{printf "%-20s %-15s %-10s\n", m, F, $2}
(-
给出左对齐;默认为右对齐,通常适用于数字,但不适用于文本。)
如果您希望宽度适应数据,您可以将数据存储在数组中,计算所需的宽度,然后使用带有星号的这些宽度,例如printf "%-*s ", len, data
-- 但是G-Man 回答了这个column
节目更容易做到这一点。
答案3
您可以通过执行以下操作使列对齐
# fcinfo hba-port | awk '
BEGIN {printf("HBA_Manufacturer Firmware_Version State\n")
printf("---------------- ---------------- -----\n")
}
/Manufacturer:/ {m=$2}
/Firmware Version:/ {F=$3}
/State/ {print m, F, $2}' | column -t
这将产生类似的输出
HBA_Manufacturer Firmware_Version State
---------------- ---------------- -----
Emulex 2.82a4 online
Emulex 2.82a4 online
Emulex 2.82a4 offline
Emulex 2.82a4 offline
Emulex 2.82a4 online
Emulex 2.82a4 online
笔记:
- 如果您希望列之间有更多空间,请使用末尾的 (或) 选项来指定要在列之间放置的字符串。默认是两个空格;例如, (有四个空格)会给您一些更接近您显示的示例输出的内容。
--output-separator string
-o string
… | column -t -o " "
您显示的示例输出在标题后面有一行连续的破折号。如上所示,我的命令只会在每个标题下给出一小行破折号。如果某些数据较长,这一点会变得更加明显:
HBA_Manufacturer Firmware_Version State ---------------- ---------------- ----- Emulex 2.82a4 online Emulex 2.82a4 online Some_other_manufacturer 2.82a4 offline Emulex 2.82a4 offline Emulex 2.82a4 online Emulex 2.82a4 online
如有必要,可以修复此问题。
答案4
你可能需要通过反复试验来调整选项卡,但大致上——
awk 'BEGIN{printf("HBA_Manufacturer\t\t\tFirmware_Version\t\t\tState\n----------------------------------------\n")} {... printf("%s\t\t\t%s\t\t\t%s\n", m, f,$2) }