Воспроизведите команду Unix cat в Python

В настоящее время я воспроизводю следующую команду 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 здесь .

Суть проблемы в том, что мой вопрос относился к (неожиданному для меня) поведению readlines. Ответ, к которому я стремился, можно было бы задать лучше, и на этот вопрос лучше было бы ответить read().splitlines().


person JBWhitmore    schedule 18.07.2012    source источник
comment
cat.py для Python 3.   -  person jfs    schedule 29.12.2015


Ответы (6)


Самый простой способ — просто забыть о строках и просто прочитать весь файл, а затем записать его в вывод:

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)
person Jonathan Callen    schedule 18.07.2012

#!/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() может быть более эффективным, чем комбинация чтения/записи, используемая другими подходами.

person jfs    schedule 19.01.2013

Итерация по файлу дает строки.

for line in infile:
  outfile.write(line)
person Ignacio Vazquez-Abrams    schedule 18.07.2012
comment
Если infile является расположением файла, то расположение файла будет напечатано сбоку. - person Josiah; 14.10.2020

Вы можете упростить это несколькими способами:

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 этого не делает, поэтому я не уверен, что вы действительно этого хотите.

person Ned Batchelder    schedule 18.07.2012

списковые включения отлично подходят для таких вещей:

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()]))
person Handyman5    schedule 22.11.2012

person    schedule
comment
Да, если бы не тот факт, что ОП явно хочет удалить пустые строки, я бы сделал это большими кусками. - person kindall; 18.07.2012
comment
Это на самом деле воспроизводит цель conCATenation cat. Браво! +1 для вас. - person bballdave025; 08.06.2018