用awk从文件中读取元组

时间:2012-07-23 07:47:27

标签: linux bash shell awk

嗨我需要一个脚本来读取/ proc / interruptts文件中带有awk的eth中断数,并找到每个CPU内核的中断总数。然后我想在bash中使用它们。文件的内容是;

      CPU0       CPU1       CPU2       CPU3

47:   33568      45958      46028      49191     PCI-MSI-edge    eth0-rx-0
48:     0          0          0          0       PCI-MSI-edge      eth0-tx-0
49:     1          0          1          0       PCI-MSI-edge      eth0
50:   28217      42237      65203      39086     PCI-MSI-edge    eth1-rx-0
51:     0          0          0          0       PCI-MSI-edge      eth1-tx-0
52:     0          1          0          1       PCI-MSI-edge      eth1
59:     114991     338765      77952     134850  PCI-MSI-edge eth4-rx-0
60:     429029     315813     710091      26714  PCI-MSI-edge eth4-tx-0
61:      5          2          1          5      PCI-MSI-edge     eth4
62:    1647083     208840    1164288     933967  PCI-MSI-edge eth5-rx-0
63:     673787    1542662     195326    1329903  PCI-MSI-edge eth5-tx-0
64:     5          6          7          4       PCI-MSI-edge      eth5

我正在使用此代码中的awk读取此文件:

#!/bin/bash

 FILE="/proc/interrupts"

 output=$(awk 'NR==1 {
 core_count = NF 
 print core_count
 next
}
/eth/ {
 for (i = 2; i <= 2+core_count; i++)
 totals[i-2] += $i
}

END {
 for (i = 0; i < core_count; i++)
 printf("%d\n", totals[i])
}
' $FILE)

core_count=$(echo $output | cut -d' ' -f1)

output=$(echo $output | sed 's/^[0-9]*//')

totals=(${output// / })

在这种方法中,我处理总核心数,然后处理每个CORE的总中断,以便在我的脚本中对它们进行排序。但是我只能处理数组中的数字lke this,

    totals[0]=22222
    totals[1]=33333

但是我需要将它们作为具有CPU核心名称的元组来处理。

    totals[0]=(cPU1,2222)
    totals[1]=(CPU',3333)

我认为我必须将名称分配给数组并将其读取为bash作为我的SED中的元组。我怎样才能做到这一点?

1 个答案:

答案 0 :(得分:0)

首先,bash中没有'tuple'这样的东西。阵列完全平坦。这意味着你要么有一个'标量'变量,要么有一个级别的标量数组。

您面临的任务有多种方法。之一:

  1. 如果你正在使用一个足够新的bash(4.2 AFAIR),你可以使用一个关联数组(哈希,地图,或者你可以调用它)。然后,CPU名称将是键,数字将是值;
  2. 创建一个普通数组(类似于perl的哈希),其中奇数索引将包含键(CPU名称),甚至包含值 - 值。
  3. 创建两个单独的数组,一个包含CPU名称,另一个包含值
  4. 只创建一个数组,CPU名称与某些符号(即=:)的值分隔开来。

  5. 让我们首先介绍方法2:

    #!/bin/bash
    
    FILE="/proc/interrupts"
    
    output=$(awk 'NR==1 {
        core_count = NF
        for (i = 1; i <= core_count; i++)
            names[i-1] = $i
        next
    }
    /eth/ {
        for (i = 2; i <= 2+core_count; i++)
            totals[i-2] += $i
    }
    
    END {
        for (i = 0; i < core_count; i++)
            printf("%s %d\n", names[i], totals[i])
    }
    ' ${FILE})
    
    core_count=$(echo "${output}" | wc -l)
    totals=(${output})
    

    请注意我已经更改的一些内容,以使脚本更简单:

    1. awk现在输出`cpu-name number',每行一个,用一个空格分隔;
    2. 核心计数不是由awk输出的(以避免预处理输出),而是从输出中的行数推断出来,
    3. totals数组是通过展平输出创建的 - 空格和换行都将被视为空格并用于分隔值。
    4. 结果数组如下所示:

      totals=( CPU0 12345 CPU1 23456 ) # ...
      

      要迭代它,你可以使用类似的东西(简单方法):

      set -- "${totals[@}}"
      while [[ $# -gt 0 ]]; do
          cpuname=${1}
          value=${2}
      
          # ...
      
          shift;shift
      done
      

      现在让我们修改方法1:

      #!/bin/bash
      
      FILE="/proc/interrupts"
      
      output=$(awk 'NR==1 {
          core_count = NF
          for (i = 1; i <= core_count; i++)
              names[i-1] = $i
          next
      }
      /eth/ {
          for (i = 2; i <= 2+core_count; i++)
              totals[i-2] += $i
      }
      
      END {
          for (i = 0; i < core_count; i++)
              printf("[%s]=%d\n", names[i], totals[i])
      }
      ' ${FILE})
      
      core_count=$(echo "${output}" | wc -l)
      declare -A totals
      eval totals=( ${output} )
      

      请注意:

      1. awk输出格式已更改为适合关联数组语义
      2. totals被声明为关联数组(declare -A),
      3. 遗憾的是,必须使用eval让bash直接处理输出。
      4. 结果数组如下所示:

        declare -A totals=( [CPU0]=12345 [CPU1]=23456 )
        

        现在你可以使用:

        echo ${totals[CPU0]}
        
        for cpu in "${!totals[@]}"; do
            echo "For CPU ${cpu}: ${totals[${cpu}]}"
        done
        

        第三种方法可以通过多种不同方式完成。假设你可以允许两次/proc/interrupts的读取,你甚至可以这样做:

        FILE="/proc/interrupts"
        
        output=$(awk 'NR==1 {
            core_count = NF
            next
        }
        /eth/ {
            for (i = 2; i <= 2+core_count; i++)
                totals[i-2] += $i
        }
        
        END {
            for (i = 0; i < core_count; i++)
                printf("%d\n", totals[i])
        }
        ' ${FILE})
        
        core_count=$(echo "${output}" | wc -l)
        names=( $(cat /proc/interrupts | head -n 1) )
        totals=( ${output} )
        

        所以,现在awk再次只输出计数,名称是通过bash直接从/proc/interrupts的第一行获得的。或者,您可以从方法(2)中获得的单个数组创建拆分数组,或者以其他方式解析awk输出。

        结果将在两个数组中:

        names=( CPU0 CPU1 )
        totals=( 12345 23456 )
        

        输出:

        for (( i = 0; i < core_count; i++ )); do
            echo "${names[$i]} -> ${totals[$i]}"
        done
        

        最后一种方法:

        #!/bin/bash
        
        FILE="/proc/interrupts"
        
        output=$(awk 'NR==1 {
            core_count = NF
            for (i = 1; i <= core_count; i++)
                names[i-1] = $i
            next
        }
        /eth/ {
            for (i = 2; i <= 2+core_count; i++)
                totals[i-2] += $i
        }
        
        END {
            for (i = 0; i < core_count; i++)
                printf("%s=%d\n", names[i], totals[i])
        }
        ' ${FILE})
        
        core_count=$(echo "${output}" | wc -l)
        totals=( ${output} )
        

        现在(常规)数组看起来像:

        totals=( CPU0=12345 CPU1=23456 )
        

        你可以解析它:

        for x in "${totals[@]}"; do
            name=${x%=*}
            value=${x#*=}
            echo "${name} -> ${value}"
        done
        

        (现在请注意,在循环中会分割CPU名称和值。)