【问题标题】:Delete all lines in a text file that do not contain a string删除文本文件中不包含字符串的所有行
【发布时间】:2012-02-15 09:26:20
【问题描述】:

所以我有一个 txt 文件,其中每一行都是一个文件路径,我想:

  1. 阅读此 txt 文件(逐行)。
  2. 删除所有不以,-,.txt 结尾的行
  3. 在其余行中,删除从最后一个 /,-,.txt 的所有内容。
  4. 将输出写入新的 txt。

如何使用 sed 来做到这一点?

输入:

/a/b1/
/a/b1/car
/a/b1/car/bil/
/a/b1/car/bil/,-,.txt
/a/b2/
/a/b2/flower
/a/b2/flower/bil/
/a/b2/flower/bil/,-,.txt
/a/b2/
/a/b2/boat
/a/b2/boat/baat/
/a/b2/boat/baat/abc,-,.txt

第二步:

/a/b1/car/bil/,-,.txt
/a/b2/flower/bil/,-,.txt
/a/b2/boat/baat/abc,-,.txt

第三步/期望的输出:

/a/b1/car/bil/
/a/b2/flower/bil/
/a/b2/boat/baat/

【问题讨论】:

  • 一个简短的测试样本源就可以了。否则,每个人都必须自己生产。
  • sed 是一个流编辑器。它不会将整个文件读入内存;它(通常)一次读取和处理一行。这应该正是您所需要的(忽略#1)。

标签: shell sed


【解决方案1】:
sed -n '/,-,\.txt$/s|/[^/]*$||p' input.txt > output.txt

它的作用:

它从input.txt一次读取一行; -n 告诉它默认不打印行。对于与模式,-,\.txt$ 匹配的每一行,将删除由/ 字符后跟零个或多个非/ 字符组成的所有内容,直到行尾(即,从last / 到行尾);我使用| 作为分隔符,所以我不必转义/

这是对您的要求的相当直接的表述。

既然您已经发布了示例输入和输出,我看到您想保留最终的/(这与您的要求“删除从最后一个/,-,.txt”的所有内容不一致)。为此:

sed -n '/,-,\.txt$/s|/[^/]*$|/|p' input.txt > output.txt

根据您的样本输入,这会产生您预期的结果。

如果我是即时执行此操作,我可能会使用更简单的方法,结合sedgrep

grep ',-,\.txt$' input.txt | sed 's|/[^/]*$|/|' > output.txt

【讨论】:

    【解决方案2】:
    echo -e "foo,-,.txt\nbar,-,.png" | sed -rn '/,-,\.txt/{s/^(.*),-,\.txt$/\1/p}'
    

    解释:

    sed -rn : 
        -r  : use regular expressions, which allows (.*) as  
              capturing group without masking the parens. 
        -n  : no output by default 
        '/pattern/{ list of commands}' 
        {s/pattern/replacement/p} substitute pattern with replacement,  
           then print. 
        /^(.*)foo$/ : from line begin ^ to line end $, with anything 
           before foo being captured, to be outputted with \1
    

    【讨论】:

      【解决方案3】:

      需要 sed 吗?我会用 python 来做这样的事情,sed 很快就变得复杂了。

      #!/usr/bin/env python
      import sys
      
      def main(fin, fout):
          with open(fin) as f:
              lines = []
              for line in f.readlines():
                  if line.endswith(',-,.txt\n'):
                      lines.append('/'.join(line.split('/')[:-1]) + '/\n')
      
          with open(fout, 'w') as f:
              for line in lines:
                  f.write(line)
      
      def usage():
          print sys.argv[0], "filename new_file"
          print 'remove all lines not ending with ",-,.txt"'
          print 'print the resulting lines, up to their last "/" to new file'
      
      
      if __name__ == '__main__':
          if len(sys.argv) == 3:
              main(sys.argv[1], sys.argv[2])
          else:
              usage()
      

      用样品测试

      /a/b1/car/bil/
      /a/b2/flower/bil/
      /a/b2/boat/baat/
      

      【讨论】:

      • 不,python就好了,(问题已更新)
      • 已更新,它应该适用于您的用例,但自那以后就有简单的 sed 答案
      • Keith 的 sed 解决方案是 24 个字符长。你真的认为这“过于复杂”吗? python 解决方案似乎要复杂得多。
      • 好吧,制作 Keith 的解决方案需要良好的 sed 知识和理解它需要解释(他很好地给出了),我同意这是一个很好的解决方案,但它真的更难理解和制作,我喜欢 sed ,请注意,但这对我来说有点黑暗艺术。当然,为此使用 python 需要大量样板代码来完成这样的任务(解决方案的核心是 3 行长)但是恕我直言,它更清晰。
      【解决方案4】:
      $ grep -oP '.*/(?=[^/]*,-,\.txt$)' input.txt
      /a/b1/car/bil/
      /a/b2/flower/bil/
      /a/b2/boat/baat/
      

      【讨论】:

        【解决方案5】:

        这应该可以完成工作:

        sed -r '/,-,\.txt$/!d' <file> | awk -F, '{print $1}'
        

        注意事项:

        • sed 命令删除与模式不匹配的行 (!d)
        • awk 命令只打印一行中的第一个字段,多个字段用逗号分隔。根据问题中提供的输入和所需输出,这似乎就是您要查找的内容。

        【讨论】:

          【解决方案6】:

          在您的问题中,您向我们展示了两个步骤,如果由 sed 在线人一次性完成,是否可以接受?

          sed -r  '/,-,\.txt/!d; s#/[^/]*$#/#' yourFile
          

          适用于您的示例数据。

          请看下面的测试:

          kent$  cat t.txt
          /a/b1/
          /a/b1/car
          /a/b1/car/bil/
          /a/b1/car/bil/,-,.txt
          /a/b2/
          /a/b2/flower
          /a/b2/flower/bil/
          /a/b2/flower/bil/,-,.txt
          /a/b2/
          /a/b2/boat
          /a/b2/boat/baat/
          /a/b2/boat/baat/abc,-,.txt
          
          kent$  sed -r  '/,-,\.txt/!d; s#/[^/]*$#/#' t.txt
          /a/b1/car/bil/
          /a/b2/flower/bil/
          /a/b2/boat/baat/
          

          【讨论】:

            【解决方案7】:

            这可能对你有用:

            sed 's/[^/]*,-,\.txt$//p;d' file
            

            【讨论】:

              猜你喜欢
              • 2018-06-28
              • 1970-01-01
              • 2018-08-31
              • 2020-01-03
              • 1970-01-01
              • 2011-09-05
              • 1970-01-01
              • 2020-07-27
              相关资源
              最近更新 更多