在Python中重现Unix cat命令

JBW*_*ore 9 python cat

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

cat command.info fort.13 > command.fort.13
Run Code Online (Sandbox Code Playgroud)

在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
Run Code Online (Sandbox Code Playgroud)

这是有效的,但必须有一个更好的方法.有什么建议?

编辑(2016):

四年后,这个问题又开始受到关注.我在这里用更长的Jupyter笔记本写了一些想法.

问题的关键在于我的问题与(我意想不到的)行为有关readlines.我可以更好地回答我的目标,这个问题可以更好地回答read().splitlines().

Jon*_*len 14

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

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())
Run Code Online (Sandbox Code Playgroud)

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

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)
Run Code Online (Sandbox Code Playgroud)


kin*_*all 7

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')
Run Code Online (Sandbox Code Playgroud)


jfs*_*jfs 5

#!/usr/bin/env python
import fileinput

for line in fileinput.input():
    print line,
Run Code Online (Sandbox Code Playgroud)

用法:

$ python cat.py command.info fort.13 > command.fort.13
Run Code Online (Sandbox Code Playgroud)

或者允许任意大行:

#!/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)
Run Code Online (Sandbox Code Playgroud)

用法是一样的.

或者在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
Run Code Online (Sandbox Code Playgroud)

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