Reproduce el comando cat de Unix en Python

Actualmente estoy reproduciendo el siguiente comando de Unix:

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

en Python con lo siguiente:

 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 

que funciona, pero tiene que haber una mejor manera. ¿Alguna sugerencia?

Edición (2016):

Esta pregunta ha vuelto a llamar la atención después de cuatro años. Escribí algunos pensamientos en un cuaderno de Jupyter más largo aquí .

El quid de la cuestión es que mi pregunta estaba relacionada con el comportamiento (inesperado por mí) de readlines . La respuesta a la que apuntaba podría haber sido mejor formulada, y esa pregunta habría sido mejor respondida con read().splitlines() .

La forma más sencilla podría ser simplemente olvidarse de las líneas, y solo leer todo el archivo, luego escribirlo en la salida:

 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()) 

Como se señaló en un comentario, esto puede causar un alto uso de memoria si alguna de las entradas es grande (ya que primero copia el archivo completo en la memoria). Si esto podría ser un problema, lo siguiente funcionará igual de bien (copiando los archivos de entrada en trozos):

 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) 
 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') 
 #!/usr/bin/env python import fileinput for line in fileinput.input(): print line, 

Uso:

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

O para permitir líneas grandes arbitrarias:

 #!/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) 

El uso es el mismo.

O en Python 3.3 usando 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 

La llamada sendfile() está escrita para Linux> 2.6.33. En principio, sendfile() puede ser más eficiente que una combinación de lectura / escritura utilizada por otros enfoques.

Iterando sobre un archivo produce líneas.

 for line in infile: outfile.write(line) 

Puedes simplificar esto de varias maneras:

 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 

Más importante aún, el módulo shutil tiene la función 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) 

Esto no omite las líneas en blanco, pero Cat tampoco hace eso, así que no estoy seguro de que realmente quieras hacerlo.

Lista de comprensiones son impresionantes para cosas como esta:

 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()]))