【问题标题】:using sed or awk to parse multipath output使用 sed 或 awk 解析多路径输出
【发布时间】:2012-08-24 08:56:47
【问题描述】:

我正在尝试为我正在编写的脚本解析 linux 上的多路径输出,但我找不到正确的 SED 或 AWK 语法来获得我想要的。我一直在浏览各种网站和 stackoverflow 示例,但运气不佳。

我想找到一种方法来制作:

temp (360a98000572d4d2d5834566c64536b46) dm-4 NETAPP,LUN
[size=20G]
2:0:0:4  sde        8:64  [active][ready]
1:0:0:4  sdm        8:192 [active][ready]
redo (360a98000572d4d2d5834566c646c366c) dm-3 NETAPP,LUN
[size=5.0G]
2:0:0:3  sdd        8:48  [active][ready]
1:0:0:3  sdl        8:176 [active][ready]

看起来像:

temp (360a98000572d4d2d5834566c64536b46) dm-4 NETAPP,LUN [size=20G] 2:0:0:4  sde        8:64  active][ready]
temp (360a98000572d4d2d5834566c64536b46) dm-4 NETAPP,LUN [size=20G] 1:0:0:4  sdm        8:192 [active][ready]
redo (360a98000572d4d2d5834566c646c366c) dm-3 NETAPP,LUN [size=5.0G] 2:0:0:3  sdd        8:48  [active][ready]
redo (360a98000572d4d2d5834566c646c366c) dm-3 NETAPP,LUN [size=5.0G] 1:0:0:3  sdl        8:176 [active][ready]

** 编辑 好的,所以更难的是,我发现没有 Netapp 的默认设置的多路径配置。这使得 NETAPP,LUN 不能保证在线。我已经开始做的事情:

/sbin/multipath -ll | grep -v "round-robin"| sed 's/\[feat.*//g' | sed ':a; $!N;s/\n\([^\n]*\[size\)/ \1/;ta;P;D'

它把尺寸放在主线上给我其他东西来匹配:

360a98000572d4d2d5834664e68323436 dm-6 NETAPP,LUN [size=50G]
\_ 1:0:0:0  sda 8:0   [active][ready]
360a98000572d4d2d5834664e68395951 dm-7 NETAPP,LUN [size=275G]
\_ 1:0:0:7  sdb 8:16  [active][ready]

但是我无法获得以下任何示例来匹配“G[$”(我知道如果有任何 TB 卷,我需要为 T 再添加一行)并给我正确的输出。

感谢以下大家的建议 **结束编辑

我知道如何清理间距,所以在我得到正确的输出后我会这样做。将开始多路径信息的行都以“LUN”结尾。服务器在每个 LUN 行(sdx 设备)下可以有 1 到 8 个路径。 “()”之前的部分可以是文本(别名),也可以是数字。

【问题讨论】:

    标签: linux bash sed awk


    【解决方案1】:

    一种方式:

    script.awk的内容:

    $1 ~ /^([[:digit:]]:){3}[[:digit:]]$/ {
        printf "%s %s\n", line, $0; 
        next;
    }
    
    ##$1 ~ /temp|redo/ {
    $0 ~ /LUN$/ {
        getline l;
        line = $0 " " l;
    }
    

    假设infile带有问题的内容,运行脚本如下:

    awk -f script.awk infile
    

    输出如下:

    temp (360a98000572d4d2d5834566c64536b46) dm-4 NETAPP,LUN [size=20G] 2:0:0:4  sde        8:64  [active][ready]                                                                                                                                
    temp (360a98000572d4d2d5834566c64536b46) dm-4 NETAPP,LUN [size=20G] 1:0:0:4  sdm        8:192 [active][ready]                                                                                                                                
    redo (360a98000572d4d2d5834566c646c366c) dm-3 NETAPP,LUN [size=5.0G] 2:0:0:3  sdd        8:48  [active][ready]                                                                                                                               
    redo (360a98000572d4d2d5834566c646c366c) dm-3 NETAPP,LUN [size=5.0G] 1:0:0:3  sdl        8:176 [active][ready]
    

    【讨论】:

    • 但是,如果开头不是以 temp 或 redo 开头怎么办。一些服务器不使用别名,因此它们使用数字代替: 360a98000572d4d2d5834664e68323436 dm-6 NETAPP,LUN [size=50G][features=1 queue_if_no_path][hwhandler=0][rw] _ round-robin 0 [prio=2][活跃] _ 1:0:0:0 sda 8:0 [活跃][就绪] 360a98000572d4d2d5834664e68395951 dm-7 NETAPP,LUN [size=275G][features=1 queue_if_no_path][hwhandler=0][rw] _ round-robin 0 [prio=2][活跃] _ 1:0:0:7 sdb 8:16 [活跃][就绪]
    • 这在我测试的几台服务器上运行良好,但后来我发现一台服务器的多路径配置错误,导致 Netapp、Lun 不存在。使用我在帖子中提供的其他信息,是否可以根据 [size=xG] 修改您的 awk 脚本以工作?
    【解决方案2】:

    我不知道输入的确切规格,但这个单行可能会对您有所帮助:

    awk '{if (/LUN$/){ prefix = $0; getline; prefix = prefix " " $0 } else {print prefix, $0} }'

    1. 检查当前行是否以 LUN 结尾(通过匹配 /LUN$/ 正则表达式)
    2. 如果匹配,则将当前行与下一行连接(使用getline 和隐式连接运算符)
    3. 如果没有匹配,则输出当前记录和prefix

    PS:您可能需要额外的线路过滤,这应该不难,只需在 else 分支中添加另一个 if 即可。

    【讨论】:

      【解决方案3】:

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

      sed '/LUN$/{N;y/\n/ /;h;d};G;s/^\([^\n]*\)\n\(.*\)/\2 \1/' file
      

      解释:

      • /LUN$/{N;y/\n/ /;h;d} 对于以LUN 结尾的行,将换行符和下一行添加到模式空间(PS)中,用空格替换换行符,将 PS 存储在保持空间(HS)中,然后删除 PS 和星号下一个周期。
      • G 对于所有其他行(路径行),附加一个换行符,后跟 PS 中 HS 的内容。
      • s/^\([^\n]*\)\n\(.*\)/\2 \1/ 将第一个换行符之前的任何内容与它后面的任何内容交换,并将换行符替换为空格,即将标题信息附加到路径行。

      【讨论】:

        【解决方案4】:

        由于多路径的性质,一个 LUN 可以有 1 个以上的路径,而不仅仅是两个。 所以 getline() 可能处于一个丑陋的循环中。 这是一个清晰的 awk 版本。您需要考虑的只是如何 标记 LUN 线、SIZE 线和 PATH 线。

        awk '/\(.*\)/ {lu=$0} /^\[size/ {size=$0} $2 ~ /sd/ {print lu, size, $0}'
        

        但 multipath -l 可以包含更复杂的信息,例如策略、参数等。

        【讨论】:

          【解决方案5】:

          使用 sed:

          sed -n '
            # if this is header append the size line
            /LUN$/{
              N;
              s/\n/ /;
              h       # and remember this
            }; 
            # if not header then append to header
            /LUN \[/!{ 
              G; 
              s/\(.*\)\n\(.*\)/\2 \1/;
              p; #and print
            }' input_file
          

          没有 cmets:

           sed -n ' /LUN$/{ N; s/\n/ /; h  }; /LUN \[/!{ G; s/\(.*\)\n\(.*\)/\2 \1/; p; }' input_file
          

          【讨论】:

            【解决方案6】:

            这是针对与您的问题类似的一整类问题的通用解决方案 - 即解析跨越多行的记录集,但记录集的行数可能不同。

            sed '/([0-9a-f]\{33\})/ i \\' input_file | \
              awk '
                BEGIN {RS=""; FS="\n"}
                {for(i=3; i<=NF; i++) {print $1,$2,$i}}
              '
            

            给予

            temp (360a98000572d4d2d5834566c64536b46) dm-4 NETAPP,LUN [size=20G] 2:0:0:4  sde        8:64  [active][ready]
            temp (360a98000572d4d2d5834566c64536b46) dm-4 NETAPP,LUN [size=20G] 1:0:0:4  sdm        8:192 [active][ready]
            redo (360a98000572d4d2d5834566c646c366c) dm-3 NETAPP,LUN [size=5.0G] 2:0:0:3  sdd        8:48  [active][ready]
            redo (360a98000572d4d2d5834566c646c366c) dm-3 NETAPP,LUN [size=5.0G] 1:0:0:3  sdl        8:176 [active][ready]
            

            此解决方案的属性

            • 标识十六进制摘要中的记录
            • 处理 1+ 路径
            • 很容易扩展以在 awk 中实现更多逻辑,因为每个多路径记录都被视为 awk 中的一条记录

            说明

            想象一下您的输入数据如下所示:

            temp (360a98000572d4d2d5834566c64536b46) dm-4 NETAPP,LUN
            [size=20G]
            2:0:0:4  sde        8:64  [active][ready]
            1:0:0:4  sdm        8:192 [active][ready]
            
            redo (360a98000572d4d2d5834566c646c366c) dm-3 NETAPP,LUN
            [size=5.0G]
            2:0:0:3  sdd        8:48  [active][ready]
            1:0:0:3  sdl        8:176 [active][ready]
            

            这很容易用 awk 解析。
            你只会告诉 awk ..

            1. 每条记录用空行分隔
            2. 每个字段本身应该只是一整行
            3. 然后,为了您想要的结果,打印“第一行,第二行,第 i 行”的组合,直到所有行(字段)都用完

            这正是上面的 awk 代码正在做的事情:
            BEGIN {RS=""; FS="\n"} 行设置记录 sep。到空行和字段 sep。换行。
            {for(i=3; i&lt;=NF; i++) {print $1,$2,$i}} 行完全符合我之前在 3.. 下概述的内容。

            您现在只需要引入空白行来分隔您的记录
            对于这个任务,我使用 sed。我只需要一个锚来发现之前引入空白行的行。这里我使用括号中的十六进制摘要。我假设它总是 33 个字符长。

            【讨论】:

              【解决方案7】:

              编辑:

              awk '/\[size=.*G\]/ { array[prev]++ } { prev = $0 } FNR!=NR { if ($0 in array) { line = $0; getline; line = line FS $0; next } else { print line, $0 } }' file.txt{,}
              

              解释:

              ## file.txt{,}    
              ## this is bash shorthand for reading the same file twice
              
              ## { prev = $0 }
              ## keep track of the last line
              
              ## /\[size=.*G\]/ { array[prev]++ }
              ## if the 'size' pattern is found, add the previous line to an array
              ## now we have an array of lines to search for
              
              ## FNR!=NR
              ## perform the following actions on the second file only
              
              ## if ($0 in array)
              ## if the line is one of our lines that we're searching for
              
              ## line = $0; getline; line = line FS $0; next
              ## store the line, get the next line join it up and go onto the next record
              
              ## else { print line, $0 }
              ## otherwise print out the 'line' and subsequent data
              

              结果:

              temp (360a98000572d4d2d5834566c64536b46) dm-4 NETAPP,LUN [size=20G] 2:0:0:4  sde        8:64  [active][ready]
              temp (360a98000572d4d2d5834566c64536b46) dm-4 NETAPP,LUN [size=20G] 1:0:0:4  sdm        8:192 [active][ready]
              redo (360a98000572d4d2d5834566c646c366c) dm-3 NETAPP,LUN [size=5.0G] 2:0:0:3  sdd        8:48  [active][ready]
              redo (360a98000572d4d2d5834566c646c366c) dm-3 NETAPP,LUN [size=5.0G] 1:0:0:3  sdl        8:176 [active][ready]
              

              【讨论】:

              • 这在我测试的几台服务器上运行良好,但后来我发现一台服务器的多路径配置错误,导致 Netapp、Lun 不存在。使用我在帖子中提供的其他信息,是否可以根据 [size=xG] 修改您的 awk 行以工作?
              猜你喜欢
              • 1970-01-01
              • 2012-04-16
              • 1970-01-01
              • 2021-02-20
              • 2011-04-07
              • 2015-01-12
              • 2013-12-11
              • 2018-05-01
              • 1970-01-01
              相关资源
              最近更新 更多