从命令输出中提取一列,即使它是空白的 bash

从命令输出中提取一列,即使它是空白的 bash

我正在尝试从命令输出中提取第二列

例如:

$ sudo /usr/sbin/pvs
  PV         VG       Fmt  Attr PSize   PFree
  /dev/sdc1  vgswap   lvm2 a--   16.00g      0
  /dev/sdc2  rootvg   lvm2 a--   48.00g   2.70g
  /dev/sde            lvm2 ---   32.00g  32.00g
  /dev/sdf            lvm2 ---   32.00g  32.00g

但问题是某些磁盘未与任何 VG 关联,因此 VG 名称为空,同时像这样提取输出

$ sudo /usr/sbin/pvs | awk '{print $2}'
VG
vgswap
rootvg
lvm2
lvm2

我想像这样提取(如果是空白则为空白)

vgswap
rootvg

答案1

使用专为后处理设计的输出格式,而不是仅供用户使用的默认格式:

$ sudo pvs --reportformat json_std | jq -r '.report[].pv[].vg_name'
vgswap
rootvg


或者要求pvs以您想要的格式获取您想要的值:

$ sudo pvs --no-headings --config 'log{prefix=""}' -o vg_name
vgswap
rootvg



通过禁用对齐和缩进并更改分隔符,可以使默认输出格式更易于后期处理:

sudo pvs --config $'report{aligned=0 separator="\t"}log{prefix=""}'

只要值不包含换行符或制表符,就可以使其变得简单 TSV,然后您可以使用以下命令进行后期处理:

假设列始终vg_name具有VG标题:

mlr --tsvlite --headerless-csv-output  cut -f VG

或者:

awk 'NR==1{for (i = i; i <= NF; i++) h[$i]=i; next}
     {print $ h["VG"]}'

或者,假设该vg_name列始终是第二列:

awk -F'\t' 'NR > 1 {print $2}'

在不更改输出格式的情况下,假设设备名称不包含换行符或其他控制字符或多字节字符,并且依赖于 VG 名称不能包含空格的事实,您可以将VG第一个标题行中字符串的偏移量记录为知道在后续行中在哪里查找相应的值:

sudo pvs | awk '
  NR == 1 {offset = index($0, "VG"); next}
  {$0 = substr($0, offset); sub(/ .*/, ""); print}'

答案2

使用任何 awk:

$ cat file | awk 'NR==1{n=NF; next} {print (NF<n ? "" : $2)}'
vgswap
rootvg


这只是设置n为输出第一行的字段数,然后如果存在该数量的字段则打印 $2 ,否则打印其余行的空字符串。

您也可以使用 GNU awk ,因为FIELDWIDTHS您似乎有固定宽度字段在您的输入中:

$ cat file | awk -v FIELDWIDTHS='13 9 *' 'NR>1{print $2}'
vgswap
rootvg


在您的系统上替换cat file为。sudo /usr/sbin/pvs

相关内容