2012-07-18 25 views
6

Actualmente estoy reproducción de los siguientes comandos de Unix:reproducir el comando cat Unix en Python

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 manera mejor . ¿Alguna sugerencia?

Edición (2016):

Esta pregunta ha comenzado a recibir la atención de nuevo después de cuatro años. Escribí algunos pensamientos en un Jupyter Notebook here más largo.

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 haberse preguntado mejor, y esa pregunta habría sido mejor respondida con read().splitlines().

+0

['cat.py' para Python 3] (https://gist.github.com/zed/cda879d141081e5764bd). – jfs

Respuesta

11

La forma más sencilla podría ser simplemente olvidarse de las líneas, y acaba de leer en todo el archivo, a continuación, escribir a 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 cualquiera de las entradas es grande (ya que primero copia todo el archivo en la memoria). Si esto puede 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) 
+1

Debería al menos usar 'shutil.copyfileobj' ... –

1

Iteración sobre un archivo produce líneas.

for line in infile: 
    outfile.write(line) 
6
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') 
+0

+1. Posiblemente para leer/escribir como un bloque, no líneas. – pepr

+1

Sí, si no fuera por el hecho de que aparentemente el OP quiere quitar líneas en blanco, lo haría en trozos más grandes. – kindall

1

puede simplificar esto en varias formas:

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 

que es más importante, 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 pasa por alto las líneas en blanco, pero el gato no hace eso tampoco, así que no estoy seguro de que realmente quiere.

1

List comprehensions 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()])) 
5
#!/usr/bin/env python 
import fileinput 

for line in fileinput.input(): 
    print line, 

de uso:

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

o para permitir grandes líneas 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 utilizando 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 

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