2012-07-18 8 views
6

でUnixのcatコマンドを再現私は現在、次のUNIXコマンドを再現しています:は、Python

Pythonで
cat command.info fort.13 > command.fort.13 

次のように:

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

この質問は4年後、再び注目を集め始めています。ジュピターノートブックhereの中にいくつかの考えを書きました。

問題の要点は、私の疑問がreadlinesの(私の予期しない)動作に関連していたことです。私が目指していた答えはよりよく尋ねられました。その質問はread().splitlines()でうまく答えられました。

+0

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

答えて

11

ラインを忘れ、ちょうどファイル全体を読み込み、その後、出力にそれを書くことだけであるかもしれない最も簡単な方法:

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) 
+1

少なくとも 'shutil.copyfileobj'を使うべきです... –

1

ファイルを反復すると、行が生成されます。

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。線ではなく、1つのブロックとして読み書きする可能性があります。 – pepr

+1

はい、OPが明らかに空白行を削除したいと思っていないのであれば、私はもっと大きな塊でやっています。 – kindall

1

あなたはいくつかの方法でこれを簡素化することができます。

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) 

これは、空白行をスキップしませんが、猫はどちらかそれをしないので、私はあなたが本当にしたいかわかりません。

1

List comprehensionsは、このようなことのために素晴らしいです:

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, 

使用法:

$ 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()は、他のアプローチで使用される読み取り/書き込みの組み合わせより効率的です。