从下面行的搜索列索引中提取字符串?

从下面行的搜索列索引中提取字符串?

我正在尝试制作一个简单的磁盘使用 shell 脚本(用破折号表示),但不确定如何解析该字符串,因为我不熟悉 AWK 的语法。

我使用这个命令:df -P -BG /,例如,它给我一个像这样的输出:

Filesystem                  xxxxxxxxxx-blocks  Used Available Capacity Mounted on
/dev/mapper/xxx_crypt                    500G  200G      100G      xx% /

我想在“已使用”(最终“可用”)下提取下面的列,但不确定应该如何做。我知道 AWK 有一个这样的搜索命令:awk '/Used/ {print}'

但我不知道如何获得它下面的行。有小费吗?对我来说,它作为一行上的管道工作非常重要,例如df -P -BG / | awk '...'因为我将它存储在 shell 变量中,但我认为这并不是绝对必要的,因为可以使用多行 AWK。

答案1

如果您的df实现支持它,您可以使用--output而不是解析。来自man df我的 Arch Linux:

--output[=FIELD_LIST]
  use the output format defined by FIELD_LIST, or print all fields if
  FIELD_LIST is omitted.

[...]

FIELD_LIST is a comma-separated list of columns to be included.  
Valid field names  are:  'source',  'fstype',  'itotal',  'iused',
'iavail',  'ipcent', 'size', 'used', 'avail', 'pcent', 
'file' and 'target' (see info page).

因此,就您而言,您只需这样做:

$ df  -BG --output="used" /
 Used
  200G

如果您确实需要解析它,我根本不会为模式匹配而烦恼。您控制输入,它不会改变,所以您可以只打印第三个字段(从我的系统输出):

$ df -P -BG / | awk '{print $3}'
Used
44G

如果你真的需要让它工作,即使字段顺序发生变化,所以你需要找到哪个字段包含 string Used,你可以做一些复杂的事情,如下所示:

$ df -P -BG / | 
   awk '{ if(NR==1){for(i=1; i<=NF; i++){ if($i ~ /Used/){want=i}}} print $want}'
Used
44G

答案2

将 GNU awk 用于 FPAT、FIELDIDTHS、\s、\S 和 gensub():

$ cat tst.awk
BEGIN { FPAT="\\S+|\\s+"; OFS="\t" }
NR == 1 {
    sub(/Mounted on/,"Mounted_on")
    for ( i=1; i<=NF; i+=2 ) {
        tags[++numTags] = $i
        wids = wids " " length($i $(i+1))
    }
    FIELDWIDTHS = wids
    $0 = $0
}
{
    for ( i=1; i<=NF; i++ ) {
        f[tags[i]] = gensub(/^\s+|\s+$/,"","g",$i)
    }
    print f["Filesystem"], f["Available"], f["Used"]
}

$ cat file | awk -f tst.awk | column -s $'\t' -t
Filesystem             Available  Used
/dev/mapper/xxx_crypt  100G       200G

换成我没有的cat filedf -P -BG /我只是通过column管道使列对齐,这是没有必要的。

通过这种方法,您可以按名称打印、比较、重新排序、对您喜欢的任何列的值进行算术运算等。我唯一需要在代码中修改的是“安装于”,将空格更改为下划线。

这是一个适用于任何 awk 的版本:

$ cat tst.awk
BEGIN { OFS="\t" }
NR == 1 {
    sub(/Mounted on/,"Mounted_on")
    while ( match(substr($0,totWid+1),/[^ \t]+[ \t]*/) ) {
        tag = substr($0,totWid+1,RLENGTH)
        sub(/[ \t]+$/,"",tag)
        tags[++numTags] = tag
        begs[numTags] = totWid + 1
        wids[numTags] = RLENGTH
        totWid += RLENGTH
    }
}
{
    for ( i=1; i<=numTags; i++ ) {
        val = substr($0,begs[i],wids[i])
        gsub(/^[ \t]+|[ \t]+$/,"",val)
        f[tags[i]] = val
    }
    print f["Filesystem"], f["Available"], f["Used"]
}

$ awk -f tst.awk file | column -s $'\t' -t
Filesystem             Available  Used
/dev/mapper/xxx_crypt  100G       200G

答案3

使用(以前称为 Perl_6)

~$ raku -e 'my $target = "Used"; 
            my @table = lines.map: *.split(/ \h+ /).List; 
            my $col = @table.head.grep(/ $target /, :k).cache; 
            .put for @table.map: *.[ $col.flat ];'   file

上面是用 Raku(Perl 编程语言家族的成员)编写的答案。简而言之,$声明了 -sigiled 标量并为其分配了字符串“Used”。然后lines读入,每个mapped 进入split水平\h空白。通常,这样的返回将保存在SeqRaku 中称为 a 的轻量级数据结构中,但这里我们强制将List数据保存在@table数组中。

现在来看正确的列。我们获取@table.head表格的原始标题行(即行)。我们grep通过这些元素来找到 的匹配项$target,然后我们获取:k键,即列索引号,将它们存储在 中$col。最后,我们输出put数据@a.table,只返回$col所需的列。

输入示例:

Filesystem                  xxxxxxxxxx-blocks  Used Available Capacity Mounted on
/dev/mapper/xxx_crypt                    500G  200G      100G      xx% /

示例输出:

Used
200G

OP 表达了希望有一个接受 shell 变量的脚本。 Raku 有一个特殊的关联数组%*ENV,可用于访问 shell 变量。因此,下面colName从环境(即 shell)中获取 shell 变量:

~$ env colName="Used" raku -e 'my $target = %*ENV<colName>;   \
                      my @table = lines.map: *.split(/ \h+ /).List;     \
                      my $col = @table.head.grep(/$target/, :k).cache;  \
                      .put for @table.map: *.[ $col.flat ];'   file
Used
200G

您可以类似地返回两列等,只需稍作调整,如下所示:

~$ env colNames="Used Available" raku -e '   \
                      my @target = %*ENV<colNames>.split(/ \h+ /).List;  \
                      my @table = lines.map: *.split(/ \h+ /).List;      \
                      my @col = @table.head.grep(/@target/, :k);         \
                      .put for @table.map: *.[ @col.flat ];'   file
Used Available
200G 100G

https://docs.raku.org/routine/grep
https://raku.org

相关内容