【问题标题】:grep / sed: How to print *something* when nothing matchesgrep / sed:当没有匹配项时如何打印 *something*
【发布时间】:2013-04-14 19:31:28
【问题描述】:

感谢阅读。

我有一个包含一些简单用户信息的纯文本文件

问题是,有时其中一项丢失了。

注意 Norman 和 Reggie 如何显示电子邮件地址,但 Missy 没有:

Name: Norman Normalrecord
Email: norman@ooga.com
Addr: 123 Main street

Name: Missy Missington
Addr: 789 Back street

Name: Reggie Regularrecord
Email: reggie@booga.com
Addr: 456 Middle street

我想 grep / sed 并说“如果找不到电子邮件地址,请用文本 missing_email_addr 替换”,所以我得到了这个结果:

Norman Normalrecord
norman@ooga.com
123 main street

Missy Missington
MISSING_EMAIL_ADDR
789 back street

Reggie Regularrecord
reggie@booga.com
456 middle street

问题是,在我所有的实验中,当什么都没有找到时,grep / sed 绝对不会产生任何结果,所以我什至无法对 global-replace 进行第二次传递。

我的梦想是(显然是伪 grep),它提供在搜索未找到任何内容时要打印的内容:

grep /Name:/MISSING_NAME/email:/MISSING_EMAIL_ADDR/Addr:/MISSING_STREET_ADDR/

有没有办法做这样的事情?再次感谢。

【问题讨论】:

  • 人与人之间总是有一个空行吗?

标签: sed awk grep


【解决方案1】:

这是一个开始。它将丢失的电子邮件行替换为“电子邮件:不适用”。

awk -v RS='\n\n' -v FS='\n' -v OFS='\n' \
    '{ if (!$3) $3 = "Email: N/A"; print; print "" }' users.txt

输出:

Name: Norman Normalrecord
Email: norman@ooga.com
Addr: 123 Main street

Name: Missy Missington
Addr: 789 Back street
Email: N/A

Name: Reggie Regularrecord
Email: reggie@booga.com
Addr: 456 Middle street

【讨论】:

  • 这里和 OP 有同样的问题。这不起作用;如果 $0 为空,打印语句似乎会被忽略;即,if (!$0) print "Nothing" 没有输出。
【解决方案2】:

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

sed '/^Name: /!b;:a;$!N;/\nAddr: /!ba;/\nEmail: /!s/\n/&Email: MISSING_EMAIL_ADDR&/' file

如果要删除标签:

sed -r '/^Name: /!b;:a;$!N;/\nAddr: /!ba;/\nEmail: /!s/\n/&Email: MISSING_EMAIL_ADDR&/;s/(Name|Email|Addr): //g' file

【讨论】:

    【解决方案3】:

    将 GNU awk 用于 gensub():

    $ cat tst.awk
    BEGIN { RS=""; ORS="\n\n"; FS=OFS="\n" }
    NF<3  { $3=$2; $2="Email: MISSING_EMAIL_ADDR" }
    { print gensub(/(^|\n)[^:]+:[[:space:]]*/,"\\1","g") }
    
    $ gawk -f tst.awk file
    Norman Normalrecord
    norman@ooga.com
    123 Main street
    
    Missy Missington
    MISSING_EMAIL_ADDR
    789 Back street
    
    Reggie Regularrecord
    reggie@booga.com
    456 Middle street
    

    您可以在任何 awk 中使用 sub(/^..) 然后 gsub(/\n...) 而不是 gensub(/(^|\n)...) 来做同样的事情。

    如果有用,可以识别任何缺失的字段并按照字段在您的输入中使用的顺序为其提供“缺失”指示,而无需预先明确命名任何字段(假设每个字段都出现在至少一条记录)将是:

    $ cat tst.awk
    BEGIN { RS=""; FS=OFS="\n" }
    {
       for (fldNr=1; fldNr<=NF; fldNr++) {
    
          split($fldNr,nameVal,/:[[:space:]]*/)
    
          name = nameVal[1]
          val  = nameVal[2]
    
          rec[NR,name] = val
    
          if (!seen[name]++) {
             for (nameNr=++numNames; nameNr>fldNr; nameNr--) {
                names[nameNr] = names[nameNr-1]
             }
             names[nameNr] = name
          }
    
       }
    
    }
    
    END {
       for (recNr=1; recNr<=NR; recNr++) {
    
          for (nameNr=1; nameNr<=numNames; nameNr++) {
    
             name = names[nameNr]
             key  = recNr SUBSEP name
    
             if (key in rec) {
                print rec[key]
             }
             else {
                print "MISSING_" toupper(name)
             }
          }
    
          print ""
    
       }
    }
    $
    $ cat file
    Name: Norman Normalrecord
    Email: norman@ooga.com
    Addr: 123 Main street
    
    Name: Missy Missington
    Addr: 789 Back street
    
    Name: Reggie Regularrecord
    Email: reggie@booga.com
    Addr: 456 Middle street
    Whatever: Some useful info
    $
    $ awk -f tst.awk file
    Norman Normalrecord
    norman@ooga.com
    123 Main street
    MISSING_WHATEVER
    
    Missy Missington
    MISSING_EMAIL
    789 Back street
    MISSING_WHATEVER
    
    Reggie Regularrecord
    reggie@booga.com
    456 Middle street
    Some useful info
    

    【讨论】:

      【解决方案4】:

      这是一个sed 脚本,它似乎在做你“梦想”的事情(它假设条目用空行分隔):

      $ cat s.sed
      # collect the lines from one entry in the pattern space
      # removing the empty line for consistency
      :a; $!{N;/\n$/!ba}; s/\n$// 
      # make substitutions
      /Name:/!s/^/MISSING_NAME\n/
      /Email:/!s/\n/\nMISSING_EMAIL_ADDR\n/
      /Addr:/!s/$/\nMISSING_STREET_ADDR/
      # add an empty line back
      s/$/\n/p
      

      使用您的数据:

      $ sed -nf s.sed info.txt 
      Name: Norman Normalrecord
      Email: norman@ooga.com
      Addr: 123 Main street
      
      Name: Missy Missington
      MISSING_EMAIL_ADDR
      Addr: 789 Back street
      
      Name: Reggie Regularrecord
      Email: reggie@booga.com
      Addr: 456 Middle street
      

      另一个演示:

      $ cat info_ext.txt 
      Email: norman@ooga.com
      Addr: 123 Main street
      
      Name: Missy Missington
      Addr: 789 Back street
      
      Name: Reggie Regularrecord
      Email: reggie@booga.com
      
      $ sed -nf s.sed info_ext.txt 
      MISSING_NAME
      Email: norman@ooga.com
      Addr: 123 Main street
      
      Name: Missy Missington
      MISSING_EMAIL_ADDR
      Addr: 789 Back street
      
      Name: Reggie Regularrecord
      Email: reggie@booga.com
      MISSING_STREET_ADDR
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-11-19
        • 2021-03-19
        • 2017-06-30
        • 1970-01-01
        • 1970-01-01
        • 2013-07-04
        • 2017-05-30
        • 2023-04-03
        相关资源
        最近更新 更多