我有一个文件,其中包含有关在虚拟机管理程序中运行的虚拟机的详细信息。我们运行一些命令并将输出重定向到文件。数据可采用以下格式。
Virtual Machine : OL6U5
ID : 0004fb00000600003da8ce6948c441bb
Status : Running
Memory : 65536
Uptime : 17835 Minutes
Server : MyOVS1.vmorld.com
Pool : HA-POOL
HA Mode: false
VCPU : 16
Type : Xen PVM
OS : Oracle Linux 6
Virtual Machine : OL6U6
ID : 0004fb00000600003da8ce6948c441bc
Status : Running
Memory : 65536
Uptime : 17565 Minutes
Server : MyOVS2.vmorld.com
Pool : NON-HA-POOL
HA Mode: false
VCPU : 16
Type : Xen PVM
OS : Oracle Linux 6
Virtual Machine : OL6U7
ID : 0004fb00000600003da8ce6948c441bd
Status : Running
Memory : 65536
Uptime : 17835 Minutes
Server : MyOVS1.vmorld.com
Pool : HA-POOL
HA Mode: false
VCPU : 16
Type : Xen PVM
OS : Oracle Linux 6
此输出因虚拟机管理程序而异,因为在某些虚拟机管理程序上我们运行着 50 多个虚拟机。上面的文件只是虚拟机管理程序的一个示例,其中我们只运行 3 个虚拟机,因此重定向的文件预计包含有关多个(N 个虚拟机)的信息
我们需要使用 awk/sed 或 shell 脚本以以下格式获取此详细信息
Virtual_Machine ID Status Memory Uptime Server Pool HA VCPU Type OS
OL6U5 0004fb00000600003da8ce6948c441bb Running 65536 17835 MyOVS1.vmworld.com HA-POOL false 16 Xen PVM Oracle Linux 6
OL6U6 0004fb00000600003da8ce6948c441bc Running 65536 17565 MyOVS2.vmworld.com NON-HA-POOL false 16 Xen PVM Oracle Linux 6
OL6U5 0004fb00000600003da8ce6948c441bd Running 65536 17835 MyOVS1.vmworld.com HA-POOL false 16 Xen PVM Oracle Linux 6
答案1
如果您有rs
(重塑)效用可用时,您可以执行以下操作:
rs -Tzc: < input.txt
这给出了与问题中指定的输出格式完全相同的格式,甚至精确到动态列宽度。
-T
转置输入数据-z
根据每列的最大值适当调整列的大小-c:
使用冒号作为输入字段分隔符
这适用于任意大小的表,例如:
$ echo "Name:Alice:Bob:Carol
Age:12:34:56
Eyecolour:Brown:Black:Blue" | rs -Tzc:
Name Age Eyecolour
Alice 12 Brown
Bob 34 Black
Carol 56 Blue
$
rs
默认情况下在 OS X(以及可能的其他 BSD 机器)上可用。它可以通过以下命令安装在 Ubuntu(和 debian 系列)上:
sudo apt-get install rs
答案2
编辑:在一个简单的单行for
循环中可扩展到任意数量的输出行:
for ((i=1;i<=2;i++)); do cut -d: -f "$i" input | paste -sd: ; done | column -t -s:
原答案:
您可以使用流程替换将其作为单行代码执行bash
:
paste -sd: <(cut -d: -f1 input) <(cut -d: -f2 input) | column -t -s:
该-s
选项paste
使其一次处理每个文件。:
设置的分隔符被最后的选项paste
“捕获” ,通过使字段对齐来美化格式。-s
column
两个进程替换中的命令cut
分别拉出第一个字段和第二个字段。
输入中是否有空行并不重要,因为column -t -s:
无论如何都会清理输出。 (问题中指定的原始输入中有空行,但它们已被删除。无论空行如何,上述命令都有效。)
输入 - 上述命令中名为“input”的文件的内容:
Virtual_Machine:OL6U7
ID:0004fb00000600003da8ce6948c441bd
Status:Running
Memory:65536
Uptime:17103
Server:MyOVS1.vmworld.com
Pool:HA-POOL
HA:false
VCPU:16
Type:Xen PVM
OS:Oracle Linux 6
输出:
Virtual_Machine ID Status Memory Uptime Server Pool HA VCPU Type OS
OL6U7 0004fb00000600003da8ce6948c441bd Running 65536 17103 MyOVS1.vmworld.com HA-POOL false 16 Xen PVM Oracle Linux 6
答案3
如果两次遍历文件不是一个(大)问题(只会在内存中存储一行):
awk -F : '{printf("%s\t ", $1)}' infile
echo
awk -F : '{printf("%s\t ", $2)}' infile
对于字段的一般计数,其中可能有许多文件路径:
#!/bin/bash
rowcount=2
for (( i=1; i<=rowcount; i++ )); do
awk -v i="$i" -F : '{printf("%s\t ", $i)}' infile
echo
done
但对于真正通用的转置,这将起作用:
awk '$0!~/^$/{ i++;
split($0,arr,":");
for (j in arr) {
out[i,j]=arr[j];
if (maxr<j){ maxr=j} # max number of output rows.
}
}
END {
maxc=i # max number of output columns.
for (j=1; j<=maxr; j++) {
for (i=1; i<=maxc; i++) {
printf( "%s\t", out[i,j]) # out field separator.
}
printf( "%s\n","" )
}
}' infile
并使其美观(使用制表符\t
作为字段分隔符):
./script | |column -t -s $'\t'
Virtual_Machine ID Status Memory Uptime Server Pool HA VCPU Type OS
OL6U7 0004fb00000600003da8ce6948c441bd Running 65536 17103 MyOVS1.vmworld.com HA-POOL false 16 Xen PVM Oracle Linux 6
上面的通用转置代码会将整个矩阵存储在内存中。
对于非常大的文件来说这可能是一个问题。
更新新文本。
为了处理问题中发布的新文本,在我看来,两遍 awk 是最好的答案。只要字段存在,一次传递将打印标题字段标题。下一个 awk 遍将仅打印字段 2。在这两种情况下,我都添加了一种删除前导空格和尾随空格的方法(为了更好的格式)。
#!/bin/bash
{
awk -F: 'BEGIN{ sl="Virtual Machine"}
$1~sl && head == 1 { head=0; exit 0}
$1~sl && head == 0 { head=1; }
head == 1 {
gsub(/^[ \t]+/,"",$1); # remove leading spaces
gsub(/[ \t]+$/,"",$1); # remove trailing spaces
printf( "%s\t", $1)
}
' infile
#echo
awk -F: 'BEGIN { sl="Virtual Machine"}
$1~sl { printf( "%s\n", "") }
{
gsub(/^[ \t]+/,"",$2); # remove leading spaces
gsub(/[ \t]+$/,"",$2); # remove trailing spaces
printf( "%s\t", $2)
}
' infile
echo
} | column -t -s "$(printf '%b' '\t')"
周围的{ ... } | column -t -s "$(printf '%b' '\t')"
是以漂亮的方式格式化整个表格。
请注意,可以用ksh、bash 或 zsh"$(printf '%b' '\t')"
替换。$'\t'
答案4
使用 awk 存储键和值并最后打印出来。
#!/usr/bin/awk -f
BEGIN {
CNT=0
FS=":"
}
{
HDR[CNT]=$1;
ENTRY[CNT]=$2;
CNT++;
}
END {
for (x = 0; x < CNT; x++)
printf "%s\t",HDR[x]
print""
for (x = 0; x < CNT; x++)
printf "%s\t",ENTRY[x]
}
刚刚跑的awk -f ./script.awk ./input.txt