如何从命令输出中获取特定元素,然后以表格格式显示?

时间:2018-01-24 03:11:45

标签: bash macos awk terminal

我倾向于频繁使用macos命令diskutil info -all并且它有比我通常想要的更多的信息,它以一种列表类型格式显示它并附加19个硬盘驱动器意味着很多滚动。我试图从diskutil info -all的输出中仅提取四位信息,然后将其格式化为一个包含四列的表。

我正在使用grep来获取我想要的确切信息:

diskutil info -all | grep -e "Device Identifier:" -e "Device Node:" -e "Volume Name:" -e "Volume UUID:"

导致如下:

   Device Identifier:        disk0
   Device Node:              /dev/disk0
   Volume Name:              Not applicable (no file system)
   Device Identifier:        disk1
   Device Node:              /dev/disk1
   Volume Name:              Not applicable (no file system)
   Device Identifier:        disk1s1
   Device Node:              /dev/disk1s1
   Volume Name:              EFI
   Device Identifier:        disk1s2
   Device Node:              /dev/disk1s2
   Volume Name:              Old-Timemachine-Lion
   Volume UUID:              D04D1888-ABD9-3480-9692-60ECA458C372
   Device Identifier:        disk1s3
   Device Node:              /dev/disk1s3
   Volume Name:              Backup-Lion
   Volume UUID:              8C737824-F790-324B-AC4C-6F398D6CE947
   Device Identifier:        disk1s4
   Device Node:              /dev/disk1s4
   Volume Name:              Old-Timemachine-Garnet
   Volume UUID:              DECBEC2C-ADFD-397E-88B6-B9CC962E00E4

我想去除第一列,然后将第二列分成四列,每个参数一列。上面的输出片段如下所示:

   disk0      /dev/disk0        Not applicable (no file system)
   disk1      /dev/disk1        Not applicable (no file system)
   disk1s1    /dev/disk1s1      EFI
   disk1s2    /dev/disk1s2      Old-Timemachine-Lion                D04D1888-ABD9-3480-9692-60ECA458C372
   disk1s3    /dev/disk1s3      Backup-Lion                         8C737824-F790-324B-AC4C-6F398D6CE947
   disk1s4    /dev/disk1s4      Old-Timemachine-Garnet              ECBEC2C-ADFD-397E-88B6-B9CC962E00E4

我发现我可以使用剪切来摆脱第一列,并认为我应该能够使用printf和命令替换格式化为列。类似的东西:

printf "%14s    %14s    %14s    %14s\n" "$(diskutil info -all | grep -e "Device Identifier:" -e "Device Node:" -e "Volume Name:" -e "Volume UUID:" | cut -c 30-70)"

它可以摆脱第一列,但不会格式化,就像printf不工作一样。输出如下:

disk0
/dev/disk0
Not applicable (no file system)
disk1
/dev/disk1
Not applicable (no file system)
disk1s1
/dev/disk1s1
EFI
disk1s2
/dev/disk1s2
Old-Timemachine-Lion
D04D1888-ABD9-3480-9692-60ECA458C372
disk1s3
/dev/disk1s3
Backup-Lion
8C737824-F790-324B-AC4C-6F398D6CE947
disk1s4
/dev/disk1s4
Old-Timemachine-Garnet
DECBEC2C-ADFD-397E-88B6-B9CC962E00E4

我对shell脚本的态度不强,所以我怀疑我的方法是最好的,但在这里缺少和/或做错了什么?我想学习。

4 个答案:

答案 0 :(得分:2)

关注awk可能对您有帮助。

awk '
/Device Identifier/{
  if(val){
    print val};
  val=$NF
}
/Device Node:/{
  val=val OFS $NF
}
/Volume Name:/{
  sub(/Volume Name:* +/,"");
  val=val OFS $0
}
/Volume UUID:/{
  sub(/Volume UUID:* +/,"");
  val=val OFS $0
}
END{
  if(val){
    print val}
}
'   Input_file

输出如下。

disk0 /dev/disk0    Not applicable (no file system)
disk1 /dev/disk1    Not applicable (no file system)
disk1s1 /dev/disk1s1    EFI
disk1s2 /dev/disk1s2    Old-Timemachine-Lion    D04D1888-ABD9-3480-9692-60ECA458C372
disk1s3 /dev/disk1s3    Backup-Lion    8C737824-F790-324B-AC4C-6F398D6CE947
disk1s4 /dev/disk1s4    Old-Timemachine-Garnet    DECBEC2C-ADFD-397E-88B6-B9CC962E00E4

答案 1 :(得分:2)

我的建议是使用awk。这正是它所做的事情。这是一个时髦的工具,但一旦你学会它,它对各种翻译/制表任务都很有用。

这是对你的问题的快速抨击:

#!/bin/awk

/Device Identifier:/ { device=$3 }
/Device Node:/ { node=$3 }
/Volume Name:/ { split($0,parts,/:/); part2=parts[2]; sub(/^[ \t]*/,"",part2); name=part2 }
/Volume UUID:/ { uuid=$3 }
/^\*+/ { printf("%-10s %-16s %-40s %s\n",device,node,name,uuid) }

将其放入文件中,然后运行diskutil info -all | awk -f ~/Desktop/that_file.awk

这只是冰山一角。 awk可以做出决定,做数学等等。这是一个穷人的perl,但是当我使用它时我发现我的头部没有爆炸。 ;)

答案 2 :(得分:1)

您可以在awk

之后使用以下diskutil info -all | grep -e "Device Identifier:" -e "Device Node:" -e "Volume Name:" -e "Volume UUID:"命令
$ diskutil info -all | grep -e "Device Identifier:" -e "Device Node:" -e "Volume Name:" -e "Volume UUID:" | awk 'BEGIN{FS=":";}/Device Identifier/{print ""}{printf $2}END{printf "\n"};' | sed -e 's/ \{3,\}/@/g;' | column -s'@' -t
disk0    /dev/disk0    Not applicable (no file system)
disk1    /dev/disk1    Not applicable (no file system)
disk1s1  /dev/disk1s1  EFI
disk1s2  /dev/disk1s2  Old-Timemachine-Lion             D04D1888-ABD9-3480-9692-60ECA458C372
disk1s3  /dev/disk1s3  Backup-Lion                      8C737824-F790-324B-AC4C-6F398D6CE947
disk1s4  /dev/disk1s4  Old-Timemachine-Garnet           DECBEC2C-ADFD-397E-88B6-B9CC962E00E4

其中

  • BEGIN{FS=":";}:
  • 定义了awk的字段分隔符
  • /Device Identifier/{print ""}每次到达新设备标识符时都会打印EOL
  • {printf $2}将使您的垂直磁盘属性水平转换
  • END{printf "\n"}打印最后一个EOL字符
  • sed -e 's/ \{3,\}/@/g;| column -s'@ -t您将其传输到sed和column以正确地重新整形它,您有以下输出:

enter image description here

答案 3 :(得分:1)

在将输入传递给sed之前,我使用awk进行了一些预处理。此外,我已使用下划线替换每个字段中的空格(希望这不是问题),以便使用column -t

提供更一致的结果
diskutil info -all |
grep -e "Device Identifier:" -e "Device Node:" -e "Volume Name:" -e "Volume UUID:" |
sed -E 's/^[[:blank:]]*(Device Identifier:.*)$/\n\1/;
s/[[:blank:]]+/ /g;
s/^[[:blank:]]+//;s/: /:/' |
awk -v RS="" -v FS=":" '{
for(i=2;i<=NF;i+=2){
gsub(/ /,"_",$i);printf "%s ",$i
}
printf "\n"
}' | column -t

<强>输出

disk0    /dev/disk0    Not_applicable_(no_file_system)
disk1    /dev/disk1    Not_applicable_(no_file_system)
disk1s1  /dev/disk1s1  EFI
disk1s2  /dev/disk1s2  Old-Timemachine-Lion             D04D1888-ABD9-3480-9692-60ECA458C372
disk1s3  /dev/disk1s3  Backup-Lion                      8C737824-F790-324B-AC4C-6F398D6CE947
disk1s4  /dev/disk1s4  Old-Timemachine-Garnet           DECBEC2C-ADFD-397E-88B6-B9CC962E00E4