【问题标题】:Bash try to count number of occurence?Bash 尝试计算出现次数?
【发布时间】:2021-02-12 21:23:02
【问题描述】:

我有这种类型的数据:

Folder : 1
Folder : 2
  VM: XXX
  VM: XXX
  VM: XXX
  VM: XXX
  VM: XXX
  VM: XXX
  VM: XXX
  VM: XXX
  VM: XXX
  VM: XXX
  VM: XXX
  VM: XXX
Folder : 3
  VM: XXX
  VM: XXX
Folder : 4
  VM: XXX
  VM: XXX
  VM: XXX
  VM: XXX
  VM: XXX
Folder : 5
Folder : 6
etc ...

我能够检索此文件中的 VM 总数:

cat my_file | grep VM | wc -l
19

但我想了解如何获得这个输出:

Folder : 1
Total VM : 0

Folder : 2
Total VM : 12

Folder : 3
Total VM : 2

Folder : 4
Total VM : 5

Folder : 5
Total VM : 0

Folder : 6
Total VM : 0
etc ...

我不知道如何用 bash 检索每个文件夹中的 VM 数量...

有人向我解释如何做到这一点?

【问题讨论】:

    标签: shell awk


    【解决方案1】:

    使用自定义RS 的简化gnu-awk

    awk -v RS='Folder *:[^\n]+' 'hdr {print hdr; print "Total VM : " gsub(/[[:space:]]*VM:/, "&") ORS} {hdr=RT}' file
    
    Folder : 1
    Total VM : 0
    
    Folder : 2
    Total VM : 12
    
    Folder : 3
    Total VM : 2
    
    Folder : 4
    Total VM : 5
    
    Folder : 5
    Total VM : 0
    
    Folder : 6
    Total VM : 0
    
    

    更易读的版本:

    # we use RS with regex as /Folder :<rest of the line?/
    # RT gives as value of matched text
    awk -v RS='Folder *:[^\n]+' '
    hdr {
       print hdr   # print header line
       # in gsub we match 0+ white space folowed by VM:
       # dummy gsub replace match with itself but it returns no of matches
       print "Total VM : " gsub(/[[:space:]]*VM:/, "&") ORS
    }
    {
       hdr = RT    # store value of RT in variable hdr
    }' file
    

    【讨论】:

    • 确实,您的可读版本更...“可读”!你能逐行解释你的 awk 命令是如何工作的吗?
    • 我已经添加了一个解释。我们也鼓励您阅读手册页
    【解决方案2】:

    您能否使用您展示的示例尝试使用 GNU awk 进行跟踪、编写和测试。

    awk '
    /^Folder/{
      if(prevFolder){
        print prevFolder ORS "Total VM : " (vmVal?vmVal:0)
      }
      vmVal=""
      prevFolder=$0
      next
    }
    NF{
      vmVal++
    }
    END{
      if(prevFolder){
        print prevFolder ORS "Total VM : " (vmVal?vmVal:0)
      }
    }
    '  Input_file
    


    第二个解决方案: 或者使用函数方法尝试以下:

    awk '
    function checkVal(value){
      if(value){
        print value ORS "Total VM : " (vmVal?vmVal:0)
      }
    }
    /^Folder/{
      checkVal(prevFolder)
      vmVal=""
      prevFolder=$0
      next
    }
    NF{
      vmVal++
    }
    END{
      checkVal(prevFolder)
    }
    ' Input_file
    

    说明:为上述代码添加详细级别的说明。

    awk '                       ##Starting awk program from here.
    function checkVal(value){   ##Creating function named checkVal by passing value variable in it.
      if(value){                ##Checking if value is NOT NULL then do following.
        print value ORS "Total VM : " (vmVal?vmVal:0)
                                ##Printing value ORS Total VM : and vmVal value or 0 if its NULL.
      }
    }
    /^Folder/{                  ##Checking condition if line starts from Folder then do following.
      checkVal(prevFolder)      ##Calling checkVal function with passing prevFolder value to it.
      vmVal=""                  ##Nullifying vmVal here.
      prevFolder=$0             ##Setting preFolder to current line here.
      next                      ##next will skip all further statements from here.
    }
    NF{                         ##Checking condition if NF is NOT NULL then do following.
      vmVal++                   ##Increment vmVal with 1 here.
    }
    END{                        ##Starting END block of this program from here.
      checkVal(prevFolder)      ##Calling checkVal function with prevFolder value here.
    }
    ' Input_file                ##Mentioning Input_file name here.
    

    【讨论】:

      【解决方案3】:

      使用 GNU awk:

      awk '/Folder/ { folder=$3;map[folder]=0;next } /VM:/ { map[folder]++ } END { PROCINFO["sorted_in"]="@ind_num_asc";for (i in map) { printf "Folder : %s\nTotal VM : %s\n\n",i,map[i] } }' file
      

      解释:

      awk '/Folder/ {                                                   # Process lines starting with "Folder"
                      folder=$3;                                        # Set variable folder to the third space delimited field
                      map[folder]=0;                                    # Initialise an array map with the folder as the index and 0 as the value.
                      next 
                    } 
              /VM:/ {                                                   # Process lines with VM
                      map[folder]++                                     # Increment the array for the folder
                    } 
                END { 
                      PROCINFO["sorted_in"]="@ind_num_asc";             '# Set array ordering
                      for (i in map) { 
                         printf "Folder : %s\nTotal VM : %s\n\n",i,map[i]      # Loop through the array and print the data in the format required.
                      } 
                    }' file
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-11-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多