2012-07-18 26 views
6

Attualmente sto riproducendo il seguente comando Unix:riprodurre il comando cat di Unix in Python

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

in Python con il seguente:

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 

che funziona, ma ci deve essere un modo migliore . Eventuali suggerimenti?

Edit (2016):

Questa domanda ha iniziato a ricevere nuovamente l'attenzione dopo quattro anni. Ho scritto alcuni pensieri su un taccuino Jupyter più lungo here.

Il nocciolo della questione è che la mia domanda riguardava il comportamento (inaspettato da me) di readlines. La risposta a cui stavo mirando avrebbe potuto essere meglio chiesta, e quella domanda avrebbe avuto una risposta migliore con read().splitlines().

+0

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

risposta

11

Il modo più semplice potrebbe essere semplicemente quello di dimenticare le linee, e appena letto l'intero file, quindi scrivere al uscita:

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

Come sottolineato in un commento , questo può causare un elevato utilizzo della memoria se uno degli ingressi è di grandi dimensioni (poiché copia prima l'intero file in memoria). Se questo potrebbe essere un problema, il seguente funziona altrettanto bene (copiando i file di input in blocchi):

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

Dovresti almeno usare 'shutil.copyfileobj' ... –

1

L'iterazione su un file produce linee.

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. Possibilmente da leggere/scrivere come un blocco, non linee. – pepr

+1

Sì, se non fosse per il fatto che l'OP a quanto pare vuole eliminare le righe vuote, lo farei in blocchi più grandi. – kindall

1

è possibile semplificare questo in pochi modi:

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 

Ancora più importante, il modulo shutil ha la funzione 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) 

Questo non salta le linee vuote, ma il gatto non lo fa neanche, quindi non sono sicuro che si vuole veramente.

1

List comprehensions sono impressionanti per cose come questa:

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, 

utilizzo:

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

o per consentire arbitrari grandi linee:

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

l'utilizzo è lo stesso .

O su Python 3.3 utilizzando 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 

È possibile che questo sendfile() chiamata viene scritto per Linux> 2.6.33.In linea di principio, sendfile() può essere più efficiente di una combinazione di lettura/scrittura utilizzata da altri approcci.

Problemi correlati