【问题标题】:Reproduce the Unix cat command in Python在 Python 中重现 Unix cat 命令
【发布时间】:2012-07-16 23:50:06
【问题描述】:

我目前正在复制以下 Unix 命令:

cat command.info fort.13 > command.fort.13

在 Python 中使用以下内容:

with open('command.fort.13', 'w') as outFile:
  with open('fort.13', 'r') as fort13, open('command.info', 'r') as com:
    for line in com.read().split('\n'):
      if line.strip() != '':
        print >>outFile, line
    for line in fort13.read().split('\n'):
      if line.strip() != '':
        print >>outFile, line

可行,但必须有更好的方法。有什么建议吗?

编辑(2016 年):

时隔四年,这个问题再次引起关注。我在更长的 Jupyter Notebook here 中写下了一些想法。

问题的症结在于我的问题与readlines 的(出乎我意料的)行为有关。我本来可以更好地提出我的目标答案,而read().splitlines() 可以更好地回答这个问题。

【问题讨论】:

标签: python cat


【解决方案1】:

最简单的方法可能是简单地忘记这些行,只需读入整个文件,然后将其写入输出:

with open('command.fort.13', 'wb') as outFile:
    with open('command.info', 'rb') as com, open('fort.13', 'rb') as fort13:
        outFile.write(com.read())
        outFile.write(fort13.read())

正如评论中所指出的,如果任何一个输入很大(因为它首先将整个文件复制到内存中),这可能会导致高内存使用。如果这可能是一个问题,以下方法也可以正常工作(通过以块的形式复制输入文件):

import shutil
with open('command.fort.13', 'wb') as outFile:
    with open('command.info', 'rb') as com, open('fort.13', 'rb') as fort13:
        shutil.copyfileobj(com, outFile)
        shutil.copyfileobj(fort13, outFile)

【讨论】:

    【解决方案2】:
    #!/usr/bin/env python
    import fileinput
    
    for line in fileinput.input():
        print line,
    

    用法:

    $ python cat.py command.info fort.13 > command.fort.13
    

    或者允许任意大行:

    #!/usr/bin/env python
    import sys
    from shutil import copyfileobj as copy
    
    for filename in sys.argv[1:] or ["-"]:
        if filename == "-":
            copy(sys.stdin, sys.stdout)
        else:
            with open(filename, 'rb') as file:
                copy(file, sys.stdout)
    

    用法相同。

    或者在 Python 3.3 上使用 os.sendfile():

    #!/usr/bin/env python3.3
    import os
    import sys
    
    output_fd = sys.stdout.buffer.fileno()
    for filename in sys.argv[1:]:
        with open(filename, 'rb') as file:
            while os.sendfile(output_fd, file.fileno(), None, 1 << 30) != 0:
                pass
    

    上述sendfile() 调用是为Linux > 2.6.33 编写的。原则上,sendfile() 可以比其他方法使用的读/写组合更有效。

    【讨论】:

      【解决方案3】:

      List comprehensions 非常适合这样的事情:

      with open('command.fort.13', 'w') as output:
        for f in ['fort.13', 'command.info']:
          output.write(''.join([line for line in open(f).readlines() if line.strip()]))
      

      【讨论】:

        【解决方案4】:

        您可以通过以下几种方式来简化:

        with open('command.fort.13', 'w') as outFile:
          with open('fort.13', 'r') as fort13, open('command.info', 'r') as com:
            for line in com:
              if line.strip():
                print >>outFile, line
            for line in fort13:
              if line.strip():
                print >>outFile, line
        

        更重要的是,shutil 模块具有 copyfileobj 功能:

        with open('command.fort.13', 'w') as outFile:
          with open('fort.13', 'r') as fort13:
            shutil.copyfileobj(com, outFile)
          with open('command.info', 'r') as com:
            shutil.copyfileobj(fort13, outFile)
        

        这不会跳过空行,但 cat 也不会这样做,所以我不确定你是否真的想要。

        【讨论】:

          【解决方案5】:
          def cat(outfilename, *infilenames):
              with open(outfilename, 'w') as outfile:
                  for infilename in infilenames:
                      with open(infilename) as infile:
                          for line in infile:
                              if line.strip():
                                  outfile.write(line)
          
          cat('command.fort.13', 'fort.13', 'command.info')
          

          【讨论】:

          • 是的,如果不是因为 OP 显然想要去除空白行,我会分大块做。
          • 这个其实是复现cat的conCATenation目的。太棒了!为你 +1。
          【解决方案6】:

          遍历文件会产生行。

          for line in infile:
            outfile.write(line)
          

          【讨论】:

          • 如果 infile 是文件的位置,这将横向打印出文件位置。
          猜你喜欢
          • 2013-07-27
          • 1970-01-01
          • 2017-03-14
          • 1970-01-01
          • 1970-01-01
          • 2014-10-11
          • 2020-07-25
          • 2015-07-15
          • 1970-01-01
          相关资源
          最近更新 更多