【问题标题】:Extract data from txt file and get concise output从txt文件中提取数据并获得简洁的输出
【发布时间】:2014-06-17 17:20:34
【问题描述】:

我需要从 .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

【问题讨论】:

  • 这不是一个人们为你编写代码的网站。您应该尝试一下,然后就可以提出更具体的问题。
  • awk -F: '/^Device/{v=$2}/^Desc/{print v $2}/^Mode/{print v$3}/^Flags/{print v$4}' output_file.txt 尝试使用 awk 并从 txt 文件中打印“Display 1 - VMware SVGA 3D - 1600 x 900 x 32 bit @ 60 Hz - Primary Device”

标签: python linux awk


【解决方案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 \ 进行转义)。这将设置特殊变量RS,即输入记录分隔符,它告诉awk 如何根据指定的正则表达式将输入分解为记录。 ($0 指的是正在处理的整个当前记录。)
  • 每条记录按行分成字段 (-F'\n') --F 设置特殊变量 FS,输入字段分隔符,它告诉 awk 如何将每条记录拆分为单独的字段 ($1, $2, ...)
  • 然后建立一个字段值字典,以便可以通过字段名称引用值,例如dict["Desc"] - 查看源代码中的 cmets。
  • 最后,单个printf 语句从感兴趣的字段值合成所需的输出字符串。

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

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

【讨论】:

  • 多行记录是个很不错的技巧!顺便说一句,感谢您改进我的答案。
【解决方案2】:

只是为了好玩,我认为您的第一次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 语法有点神秘,但非常紧凑……

【讨论】:

  • 它抛出一个错误,说“awk:非法语句输入记录号 19,文件 monitor_info.txt 源行号 1”并且似乎没有拉出模式字段...我尝试使用简单的 awk ,它可以工作,但在格式化 '/Desc/ /Mode/ /Flag/' 文件名时遇到问题 Desc = "VMware SVGA 3D" Mode = 1555 x 794 x 32-bit @ 60Hz Flags = PRIMARY_DEVICE, ATTACHED_TO_DESKTOP Desc = "VMware SVGA 3D" Flags = 0x00000000 Desc = "RDPDD Chained DD" Flags = MIRRORING_DRIVER, TS_COMPATIBLE,有什么建议吗?
  • @user3731311 我不会对脚本没有拉模式感到惊讶:我只是忘记了它......我将尽快编辑我的帖子以修复它。对于错误,您能告诉我输入文件的第 19 行是什么(如果存在的话)吗?
  • 谢谢大家终于让它工作了,但它仍然发出一些错误我确实在不同的文件中得到了输出 'BEGIN{FS="="; OFS="-"; desc=""}function display(){print dev, desc,mode,flags}/Device/{if(desc!="") display();描述="";模式="";标志="";开发=$0; gsub("Dev.*PLAY", "Display", dev)}/Desc/{desc=$2}/Mode/{mode=$2}/Flags/{flags=$2}END{display}' monitor_info.txt|cat > 输出文件.txt
  • 这是我的输入文件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 标志 = PRIMARY_DEVICE, ATTACHED_TO_DESKTOP 设备 \\.\DISPLAY2 描述 = "VMware SVGA 3D" 标志 = 0x00000000 设备 \\.\DISPLAYV1s 描述 = "RDPDD 链式 DD" 标志 = MIRRORING_DRIVER, TS_COMPATIBLE 设备 \\.\DISPLAYV2 Desc = "RDP 编码器镜像驱动程序" Flags = MIRRORING_DRIVER, TS_COMPATIBLE Device \\.\DISPLAYV3 Desc = "RDP Reflector Display Driver" Flags = MIRRORING_DRIVER, TS_COMPATIBLE
  • @user3731311 在文本文件中输入此数据时,我无法重现任何错误。我想文件末尾有控制字符。你能告诉我你文件的最后几行转储(od -xchexdump,...)吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-01-07
  • 1970-01-01
  • 2019-07-09
  • 2020-03-30
  • 1970-01-01
  • 2013-05-05
  • 1970-01-01
相关资源
最近更新 更多