繁体   English   中英

如何使用 awk 删除特定字段中的某些单词?

[英]How to remove some words in specific field using awk?

我有几行文字。 我想使用 awk 提取特定单词后的数字。

我尝试了以下代码,但它不起作用。

首先,通过以下方式创建测试文件: vi test.text 有 3 列(这 3 个字段是由其他一些使用 awk 的管道命令生成的)。

Index  AllocTres                              CPUTotal
1      cpu=1,mem=256G                         18
2      cpu=2,mem=1024M                        16
3                                             4
4      cpu=12,gres/gpu=3                      12
5                                             8
6                                             9
7      cpu=13,gres/gpu=4,gres/gpu:ret6000=2   20
8      mem=12G,gres/gpu=3,gres/gpu:1080ti=1   21

请注意此文件中有几个空字段。 我想要实现的只是将数字保留在第一个gres/gpu部分之后,并使用如下管道删除所有cpu=mem=部分: cat test.text | awk '{some_commands}' cat test.text | awk '{some_commands}'到 output 3 列:

Index  AllocTres                              CPUTotal
1                                             18
2                                             16
3                                             4
4      3                                      12
5                                             8
6                                             9
7      4                                      20
8      3                                      21

第一个解决方案:使用您显示的示例,请尝试遵循 GNU awk代码。 这会处理字段之间的空间。

awk '
FNR==1{ print; next }
match($0,/[[:space:]]+/){
  space=substr($0,RSTART,RLENGTH-1)
}
{
  match($2,/gres\/gpu=([0-9]+)/,arr)
  match($0,/^[^[:space:]]+[[:space:]]+[^[:space:]]+([[:space:]]+)/,arr1)
  space1=sprintf("%"length($2)-length(arr[1])"s",OFS)
  if(NF>2){ sub(OFS,"",arr1[1]);$2=space arr[1] space1 arr1[1] }
}
1
'   Input_file

Output 对于上面的示例代码如下:

Index  AllocTres                              CPUTotal
1                                             18
2                                             16
3                                             4
4      3                                      12
5                                             8
6                                             9
7      4                                      20
8      3                                      21


第二种解决方案:如果您不关心空格,请尝试awk代码。

awk 'FNR==1{print;next} match($2,/gres\/gpu=([0-9]+)/,arr){$2=arr[1]} 1' Input_file

说明:为以上代码添加详细说明。

awk '             ##Starting awk program from here.
FNR==1{           ##Checking condition if this is first line then do following.
  print           ##Printing current line.
  next            ##next will skip all further statements from here.
}
match($2,/gres\/gpu=([0-9]+)/,arr){  ##using match function to match regex gres/gpu= digits and keeping digits in capturing group.
  $2=arr[1]       ##Assigning 1st value of array arr to 2nd field itself.
}
1                 ##printing current edited/non-edited line here.
' Input_file      ##Mentioning Input_file name here.

使用sed

$ sed 's~\( \+\)[^,]*,\(gres/gpu=\([0-9]\)\|[^ ]*\)[^ ]* \+~\1\3 \t\t\t\t      ~' input_file
Index  AllocTres                              CPUTotal
1                                             18
2                                             16
3                                             4
4      3                                      12
5                                             8
6                                             9
7      4                                      20
8      3                                      21

这可能对你有用(GNU sed):

    sed -E '/=/!b
        s/\S+/\n&\n/2;h
        s/.*\n(.*)\n.*/\1/
        /gpu=/!{s/./ /g;G;s/(^.*)\n(.*)\n.*\n/\2\1/p;d}
        s/gpu=([^,]*)/\n\1    \n/;s/(.*)\n(.*\n)/\2\1/;H
        s/.*\n//;s/./ /g;H;g
        s/\n.*\n(.*)\n(.*)\n.*\n(.*)/\2\3\1/' file

本质上,上述解决方案涉及使用保留空间(参见此处和最终此处)作为暂存器来保存中间结果。 这些结果是通过隔离第二个字段然后再次隔离 gpu 信息来收集的。 一步一步的故事如下:

如果该行不包含第二个字段,则保留。

用换行符包围第二个字段并制作副本。

隔离第二个字段

如果第二个字段不包含 gpu 信息,请用空格替换整个字段并使用副本,相应地格式化该行。

否则,隔离 gpu 信息,将其移至行首,将 append 移至保留空间中行的副本。

同时,从模式空间中删除 gpu 信息,并将模式空间中的每个字符替换为一个空格。

将这些空间附加到副本,然后用副本覆盖模式空间。

最后,知道行的每个部分都被换行符分割,将这些部分重新组合成所需的格式。

注意解决方案取决于列的间距是真实空间。 如果文件中有制表符,则在前面添加 sed 命令s/\t/ /g (示例中制表符被 8 个空格替换)。

选择:

sed -E '/=/!b
        s/\S+/\n&\n/2;h
        s/.*(\n.*)\n.*/\1/;s/(.)(.*gpu=)([^,]+)/\3\1\2/;H
        s/.*\n//;s/./ /g;G
        s/(.*)\n(.*)\n.*\n(.*)\n(.*)\n.*$/\2\4\1\3/' file

在这个解决方案中,我没有将带有第二个字段但没有 gpu 信息的行作为一个单独的案例,而是为这个缺失的信息引入了一个占位符,并遵循相同的解决方案,就好像 gpu 信息存在一样。

awk '
FNR>1 && NF==3 {
    n = split($2, a, ",")
    for (i=1; a[i] !~ /gres\/gpu=[0-9]+,?/ && i<=n; ++i);
    sub(/.*=/, "", a[i])
    $2 = a[i]
}
NF==2 {$3=$2; $2=""}
{printf "%-7s%-11s%s\n",$1,$2,$3}' test.txt

Output:

Index  AllocTres  CPUTotal
1                 18
2                 16
3                 4
4      3          12
5                 8
6                 9
7      4          20
8      3          21

您可以根据需要调整列宽。

这假设第一列和最后一列始终有一个值,以便 NF(字段数)可用于标识字段 2。然后,如果字段 2 不为空,则以逗号分隔该字段,扫描结果数组以查找第一个匹配项gres/gpu的,去掉这个后缀,打印三个字段。 如果字段 2 为空,则倒数第二行插入一个空的 awk 字段,因此printf始终有效。

如果上面的假设是错误的,也可以通过字符索引来识别字段 2。

一个基于awk的解决方案,不需要

- array        splitting, 
- regex back-referencing,
- prior   state tracking, or 
- input    multi-passing 
  —- since m.p. for /dev/stdin would require state tracking

|

{mng}awk '!_~NF || sub("[^ ]+$", sprintf("%*s&", length-length($!(NF=NF)),_))' \
             FS='[ ][^ \\/]*gres[/]gpu[=]|[,: ][^= ]+[=][^,: ]+' OFS=

Index  AllocTres                              CPUTotal
1                                             18
2                                             16
3                                             4
4     3                                       12
5                                             8
6                                             9
7     4                                       20
8     3                                       21

如果您不关心 nawk,那么它是更简单的单遍方法,每行仅对sub()进行 1 次全面调用:

awk ' sub("[^ ]*$", sprintf("%*s&", length($_) - length($(\
     gsub(" [^ /]*gres[/]gpu=|[,: ][^= ]+=[^,: ]+", _)*_)),_))'

甚至更简洁但更糟糕的语法样式:

awk 'sub("[^ ]*$",sprintf("%*s&",length^gsub(" [^ /]*gres\/gpu=|"\
                          "[,: ][^= ]+=[^,: ]+",_)^_ - length,_) )'

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM