私はpythonを使って印刷を.txtファイルにリダイレクトしたいです。私はすべてのこれらの出力を1つのファイルにリダイレクトしたいのですが、私はそれぞれの.bamファイルの出力を '印刷'する 'for'ループがあります。だから私は入れてみました
f = open('output.txt','w'); sys.stdout = f
私の脚本の冒頭で。しかし、私は.txtファイルに何も入っていません。私のスクリプトは次のとおりです。
#!/usr/bin/python
import os,sys
import subprocess
import glob
from os import path
f = open('output.txt','w')
sys.stdout = f
path= '/home/xug/nearline/bamfiles'
bamfiles = glob.glob(path + '/*.bam')
for bamfile in bamfiles:
filename = bamfile.split('/')[-1]
print 'Filename:', filename
samtoolsin = subprocess.Popen(["/share/bin/samtools/samtools","view",bamfile],
stdout=subprocess.PIPE,bufsize=1)
linelist= samtoolsin.stdout.readlines()
print 'Readlines finished!'
........print....
........print....
だから問題は何ですか?このsys.stdout以外の何か他の方法は?
結果は次のようになります。
Filename: ERR001268.bam
Readlines finished!
Mean: 233
SD: 10
Interval is: (213, 252)
これを行う最も明白な方法は、ファイルオブジェクトに出力することです。
with open('out.txt', 'w') as f:
print >> f, 'Filename:', filename # Python 2.x
print('Filename:', filename, file=f) # Python 3.x
しかし、標準出力のリダイレクトも私にとってはうまくいきます。このような1回限りのスクリプトにはおそらく大丈夫です。
import sys
orig_stdout = sys.stdout
f = open('out.txt', 'w')
sys.stdout = f
for i in range(2):
print 'i = ', i
sys.stdout = orig_stdout
f.close()
シェル自体から外部にリダイレクトすることは、もう1つの良い選択肢です。
./script.py > out.txt
その他の質問
スクリプトの最初のファイル名は何ですか?初期化されていないようです。
私の最初の推測は、globがどんな失敗ファイルも見つけられないため、forループが実行されないことです。フォルダが存在することを確認し、スクリプト内のbamfilesを印刷します。
また、パスとファイル名を操作するには、 os.path.joinとos.path.basename を使用します。
>>
演算子を使用して印刷をリダイレクトできます。
f = open(filename,'w')
print >>f, 'whatever' # Python 2.x
print('whatever', file=f) # Python 3.x
ほとんどの場合、普通にファイルに書き込むだけの方が得策です。
f.write('whatever')
あるいは、print
のように、間にスペースを空けて書き込みたい項目がいくつかある場合は、
f.write(' '.join(('whatever', str(var2), 'etc')))
Python 2 または Python 3 APIリファレンス
print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False)
file引数は
write(string)
メソッドを持つオブジェクトでなければなりません。存在しないかNone
の場合、sys.stdout
が使用されます。表示された引数はテキスト文字列に変換されるので、print()
はバイナリモードのファイルオブジェクトでは使用できません。これらの場合は、代わりにfile.write(...)
を使用してください。
ファイルオブジェクト は通常write()
メソッドを含んでいるので、あなたがする必要があるのは ファイルオブジェクト をその引数に渡すことだけです。
with open('file.txt', 'w') as f:
print('hello world', file=f)
with open('file.txt', 'a') as f:
print('hello world', file=f)
これは完璧に動作します。
import sys
sys.stdout=open("test.txt","w")
print ("hello")
sys.stdout.close()
こんにちはこんにちはtest.txtファイルに書き込まれます。 stdout
は必ずclose
で閉じてください。そうしないと、内容がファイルに保存されません。
print
を使用せず、logging
を使用ファイルを指すようにsys.stdout
を変更することができますが、これはこの問題を処理するためのかなり不格好で柔軟性のない方法です。 print
を使用する代わりに、 logging
モジュールを使用してください。
logging
を使用すると、stdout
と同じように印刷することも、ファイルに出力を書き込むこともできます。さまざまなメッセージレベル(critical
、error
、warning
、info
、debug
)を使用して、たとえば、重大な問題のみをコンソールに出力し、マイナーコードのアクションをファイルに記録することもできます。
logging
をインポートし、logger
を取得し、処理レベルを設定します。
import logging
logger = logging.getLogger()
logger.setLevel(logging.DEBUG) # process everything, even if everything isn't printed
標準出力に印刷したい場合は、
ch = logging.StreamHandler()
ch.setLevel(logging.INFO) # or any other level
logger.addHandler(ch)
ファイルにも書き込みたい場合(ファイルにのみ書き込みたい場合)、最後のセクションを飛ばしてください。
fh = logging.FileHandler('myLog.log')
fh.setLevel(logging.DEBUG) # or any level you want
logger.addHandler(fh)
それで、あなたがprint
を使うところはどこでもlogger
メソッドのうちの1つを使う:
# print(foo)
logger.debug(foo)
# print('finishing processing')
logger.info('finishing processing')
# print('Something may be wrong')
logger.warning('Something may be wrong')
# print('Something is going really bad')
logger.error('Something is going really bad')
より高度なlogging
機能の使い方についてもっと学ぶためには、優秀な Pythonドキュメントのlogging
チュートリアル を読んでください。
最も簡単な解決策はpythonにはありません。そのシェルを通して。あなたのファイルの最初の行(#!/usr/bin/python
)から、あなたはUNIXシステムにいると思います。通常どおりにprint
ステートメントを使用し、スクリプト内でファイルをまったく開かないでください。代わりにファイルを実行すると
./script.py
ファイルを実行するには、
./script.py > <filename>
<filename>
を、出力先のファイルの名前に置き換えます。 >
トークンは、(ほとんどの)シェルに、標準出力を次のトークンで示されるファイルに設定するように指示します。
ここで言及する必要がある1つの重要なことは./script.py
を実行するために "script.py"を実行可能にする必要があることです。
./script.py
を実行する前に、このコマンドを実行してください。
chmod a+x script.py
(すべてのユーザーに対してスクリプトを実行可能にする)
あなたはこの答えが気に入らないかもしれませんが、私はそれが正しい答えだと思います。どうしても必要な場合以外は、標準出力先を変更しないでください(おそらく標準出力にのみ出力するライブラリを使用しているのでしょうか?明らかにここでは当てはまりません)。
良い習慣として、あなたはデータを文字列として事前に準備し、それからあなたのファイルを開いて一度に全部を書くべきだと思います。これは、ファイルハンドルを開いている時間が長いほど、入出力操作によってこのファイルでエラーが発生する可能性が高いためです(ファイルロックエラー、入出力エラーなど)。 1回の操作ですべてを実行しただけで、問題が発生した可能性がある場合は問題ありません。
これが例です:
out_lines = []
for bamfile in bamfiles:
filename = bamfile.split('/')[-1]
out_lines.append('Filename: %s' % filename)
samtoolsin = subprocess.Popen(["/share/bin/samtools/samtools","view",bamfile],
stdout=subprocess.PIPE,bufsize=1)
linelist= samtoolsin.stdout.readlines()
print 'Readlines finished!'
out_lines.extend(linelist)
out_lines.append('\n')
そして、リスト項目ごとに1行ずつ「データ行」を収集し終えたら、それらすべてを'\n'
文字で結合して、全体を出力可能にすることができます。安全性を高めるために、出力ステートメントをwith
ブロックでラップすることもできます(問題が発生しても出力ハンドルを自動的に閉じます)。
out_string = '\n'.join(out_lines)
out_filename = 'myfile.txt'
with open(out_filename, 'w') as outf:
outf.write(out_string)
print "YAY MY STDOUT IS UNTAINTED!!!"
ただし、書き込むデータがたくさんある場合は、一度に1つずつ書き込むことができます。私はそれがあなたのアプリケーションに関連するとは思いませんが、これが代替案です:
out_filename = 'myfile.txt'
outf = open(out_filename, 'w')
for bamfile in bamfiles:
filename = bamfile.split('/')[-1]
outf.write('Filename: %s' % filename)
samtoolsin = subprocess.Popen(["/share/bin/samtools/samtools","view",bamfile],
stdout=subprocess.PIPE,bufsize=1)
mydata = samtoolsin.stdout.read()
outf.write(mydata)
outf.close()
もしあなたがlinuxを使用している場合、tee
コマンドを使用することをお勧めします。コードの中で何かを変更したくない場合、実装はこのpython python_file.py |tee any_file_name.txt
のようになります。コードで。
Sys.stdoutの値を変更すると、printへのすべての呼び出しの宛先が変わります。別の方法で印刷先を変更しても、同じ結果になります。
あなたのバグは他の場所にあります。
stdout
のリダイレクトがあなたの問題に対してうまくいくなら、 Gringo Suaveの答え がそれを行う方法の良いデモンストレーションです。
それをさらに簡単にするために、私は contextmanagers を使って簡潔で一般化された呼び出し構文を利用するバージョンを作りましたwith
ステートメント:
from contextlib import contextmanager
import sys
@contextmanager
def redirected_stdout(outstream):
orig_stdout = sys.stdout
try:
sys.stdout = outstream
yield
finally:
sys.stdout = orig_stdout
これを使用するには、(Suaveの例から派生した)次のようにします。
with open('out.txt', 'w') as outfile:
with redirected_stdout(outfile):
for i in range(2):
print('i =', i)
モジュールが好きではない方法でそれを使うとき、それはprint
を選択的にリダイレクトするのに役に立ちます。唯一の不利な点(そしてこれは多くの状況での問題を解決するためのものです)はstdout
の値が異なる複数のスレッドが欲しい場合にはうまく行かないということです。あなたはこの質問に対する他の答えでそれの実装を見ることができます。