从txt文件中提取数据并获得简洁的输出

时间:2014-06-17 17:20:34

标签: python linux awk

我需要从.txt文件中提取一些信息并获得简洁的输出行 输出应该如下: Display 1 - VMware SVGA 3D - 1600 x 900 x 32 bit @ 60 Hz - Primary Device

文本文件包含以下信息:

ws_diag 5.3.0 build-1427931
Device \\.\DISPLAY1
   Desc = "VMware SVGA 3D"
   Mode = 1555 x 794 x 32-bit @ 60Hz
   Bounds = 0,0  1555,794
   Flags = PRIMARY_DEVICE, ATTACHED_TO_DESKTOP
Device \\.\DISPLAY2
   Desc = "VMware SVGA 3D"
   Flags = 0x00000000
Device \\.\DISPLAYV1
   Desc = "RDPDD Chained DD"
   Flags = MIRRORING_DRIVER, TS_COMPATIBLE
Device \\.\DISPLAYV2
   Desc = "RDP Encoder Mirror Driver"
   Flags = MIRRORING_DRIVER, TS_COMPATIBLE
Device \\.\DISPLAYV3
   Desc = "RDP Reflector Display Driver"
   Flags = MIRRORING_DRIVER, TS_COMPATIBLE
monitor-info.txt (END) 

这是我到目前为止所做的:

import sys
file = open(monitor-info.txt[1])
while 1:
    line = file.readline()
    tpl = line.split(":")
    if tpl[0] == "Desc":
        var = tpl[0]
    if tpl[1] == "Mode":
        print var, tpl[1]
    if tpl[2] == "Flag":
        var = tpl[2]
    print var
       if not line:
        break

我还试过awk

awk -F: '/^Device/{v=$2}/^Desc/{print v $2}/^Mode/{print v$3}/^Flags/{print v$4}' output_file.txt

2 个答案:

答案 0 :(得分:1)

使用GNU awk

gawk -F'\n' -v RS='Device \\\\\\\\.\\\\' '
    NF > 2 { # ignore the extraneous very first line
      delete dict # delete dictionary from previous record
      dict["Device"] = $1 # store device name
      for (i=2;i<NF;++i) { # store other fields in dict.
        split($i, tkns, / = /) # split into field name (e.g., "Desc") and value 
          # clean up strings (remove leading spaces from field name, remove
          # double quotes from value, and store in dictionary.
        dict[gensub(/^ +/, "", "", tkns[1])] = gensub(/"/, "", "g", tkns[2])
      }
        # Output desired fields, using the dictionary.
      printf "%s - %s - %s - %s\n", dict["Device"], dict["Desc"], dict["Mode"], dict["Flags"]
    }
  ' file

基本方法:

  • 将输入分为记录,每个记录包含与给定显示相关的所有行:-v RS='Device \\\\\\\\.\\\\'(请注意,输入中的每个文字\必须使用 3 {进行转义{1}})。这将设置特殊变量\,即输入记录分隔符,它告诉RS如何根据指定的正则表达式将输入分解为记录。 (awk然后引用正在处理的整个当前记录。)
  • 每个记录按行划分为字段($0) - -F'\n'设置特殊变量-F,输入字段分隔符,告诉FS如何拆分每条记录到单个字段(awk$1,...)
  • 然后建立字段值的字典,以便可以通过字段名称来引用值,例如, $2 - 请参阅源代码中的注释。
  • 最后,单个dict["Desc"]语句从感兴趣的字段值合成所需的输出字符串。

注意:使用了以下特定于GNU的非POSIX功能:

  • printf值不仅仅是单个字符
  • RS函数,用于灵活的基于正则表达式的字符串替换(比POSIX gensub() / sub函数更灵活)
  • 使用gsub语句删除整个数组。

答案 1 :(得分:0)

只是为了好玩,我觉得你的第一次awk尝试并不遥远。您只需将字段分隔符设置为:-F:),它应为=

也许你可以试试:

awk 'BEGIN{FS="="; OFS=" - "; desc=""}function display(){print dev, desc, flags}/Device/{if(desc!="") display(); desc=""; flags=""; dev=$0; gsub("Dev.*PLAY", "Display ", dev)}/Desc/{desc=$2}/Flags/{flags=$2}END{display}'

这是做什么的:

  • 在开头,将字段分隔符设置为=,并将字段分隔符输出到-(用于格式化)
  • 定义了一个函数display来打印一行,因为它将被调用2次
  • 如果行包含Device,则打印前面的设备(如果有),存储设备的ID并重置所有其他变量
  • 如果行包含Desc(或Mode),则将第二个字段存储在相应的变量中
  • 在文件末尾,打印最后一个设备

所有这些都会产生:

Display 1 - "VMware SVGA 3D" - PRIMARY_DEVICE, ATTACHED_TO_DESKTOP
Display 2 - "VMware SVGA 3D" - 0x00000000
Display V1 - "RDP Encoder Mirror Driver" - MIRRORING_DRIVER, TS_COMPATIBLE
Display V2 - "RDP Encoder Mirror Driver" - MIRRORING_DRIVER, TS_COMPATIBLE
Display V3 - "RDP Encoder Mirror Driver" - MIRRORING_DRIVER, TS_COMPATIBLE

awk语法有点神秘,但非常紧凑...