Pythonプログラムを適切なUNIXツールのように動作させるにはどうすればよいですか?


24

いくつかのPythonスクリプトがあり、それらの書き直しに取り組んでいます。私はそれらすべてに同じ問題を抱えています。

適切なUNIXツールのように動作するようにプログラムを記述する方法は明らかではありません。

これは

$ cat characters | progname

この

$ progname characters

同じ出力を生成するはずです。

Pythonで見つけられた最も近いものはfileinputライブラリでした。残念ながら、Pythonスクリプトを書き換える方法は実際にはわかりません。これらはすべて次のようになります。

#!/usr/bin/env python 
# coding=UTF-8

import sys, re

for file in sys.argv[1:]:
    f = open(file)
    fs = f.read()
    regexnl = re.compile('[^\s\w.,?!:;-]')
    rstuff = regexnl.sub('', fs)
    f.close()
    print rstuff

ファイル入力ライブラリは、stdinがある場合はstdinを処理し、ファイルがある場合はファイルを処理します。しかし、それは単一行にわたって反復します。

import fileinput
for line in fileinput.input():
    process(line)

私は本当にそれを得ません。あなたが小さなファイルを扱っている場合、またはあなたがファイルに多くのことをしていないなら、これは明白に見えるかもしれません。しかし、私の目的では、上記のようにファイル全体を開いて文字列に読み込むよりもはるかに遅くなります。

現在、上記のスクリプトを次のように実行しています

$ pythonscript textfilename1 > textfilename2

しかし、私はそれをパイプで実行することができます

$ grep pattern textfile1 | pythonscript | pythonscript | pythonscript > textfile2

回答:


9

どうして

files = sys.argv[1:]
if not files:
    files = ["/dev/stdin"]

for file in files:
    f = open(file)
    ...

12
sys.stdinファイルへのハードコードパスよりも移植性が高いため、代わりに使用する必要があります。
ピョートルドブロゴスト

sys.stdinピョートルが言うように、代わりに使用する必要があります
SMCI

ただしsys.stdin、ファイルであり、既に開いているため、閉じないでください。フープを介さずにファイル引数のように処理することはできません
アレクシス

@alexisもちろん、閉じたい場合f、またはコンテキストマネージャを使用したい場合は、もっと複雑なものが必要です。別の方法として私の新しい答えをご覧ください。
ミケル

12

ファイル名が引数として指定されているかどうかを確認します。指定されていない場合は、から読み取りますsys.stdin

このようなもの:

if sys.argv[1]:
   f = open(sys.argv[1])
else:
   f = sys.stdin 

sysモジュールを使用することを除いて、Mikelの答えに似ています。彼らがそこにそれを持っているかどうかは、それは理由があるに違いない...


コマンドラインで2つのファイル名を指定した場合はどうなりますか?
ミケル

3
絶対に!それはあなたの答えに既に示されていたので、私はそれを気にしませんでした。ある時点で、ユーザーが必要なものを決定するためにユーザーを信頼する必要があります。ただし、これが最善であると思われる場合は、自由に編集してください。私のポイントは交換することである"open(/dev/stdin")sys.stdin
ラーム

2
そうではif len(sys.argv)>1:なく、チェックすることをお勧めします。if sys.argv[1]:範囲外のエラーが発生します
Yiboヤン

3

私の好ましいやり方は...(そして、これはHarbinger's Hollowという素敵な小さなLinuxブログから取られています)

#!/usr/bin/env python

import argparse, sys

parser = argparse.ArgumentParser()
parser.add_argument('filename', nargs='?')
args = parser.parse_args()
if args.filename:
    string = open(args.filename).read()
elif not sys.stdin.isatty():
    string = sys.stdin.read()
else:
    parser.print_help()

私がこれが一番好きだった理由は、ブロガーが言うように、入力せずに誤って呼び出された場合に愚かなメッセージを出力するだけだからです。また、既存のすべてのPythonスクリプトに非常にうまく収まるので、すべてを含めて変更しました。


3
時々、ttyから対話形式で入力を行いたいことがあります。チェックisattyと救済は、Unixフィルターの哲学に準拠していません。
ムシフィル

isattyいぼとは別に、これは他の答えにはない有用で重要な根拠をカバーしているので、私の賛成を得ます。
トリプリー

3
files=sys.argv[1:]

for f in files or [sys.stdin]:
   if isinstance(f, file):
      txt = f.read()
   else:
      txt = open(f).read()

   process(txt)

これは/dev/stdin、すべてのシステムで使用できなかった場合に、私が書いた方法です。
ミケル

0

私はこのソリューションを使用していますが、それは魅力のように機能します。実際、私は特定の文字列の小文字を使用してアクセントを削除する無声アクセントをスクリプトで使用しています

argument = sys.argv[1:] if len(sys.argv) > 1 else sys.stdin.read()

この解決策を見た最盛期はここにあっと思う。


0

システムにがない場合/dev/stdin、またはより一般的なソリューションが必要な場合は、次のようなより複雑なものを試すことができます。

class Stdin(object):
    def __getattr__(self, attr):
        return getattr(sys.stdin, attr)

    def __enter__(self):
        return self

def myopen(path):
    if path == "-":
        return Stdin()
    return open(path)

for n in sys.argv[1:] or ["-"]:
    with myopen(n) as f:
            ...

終了時にファイルポインターを移動するのはなぜですか?悪いアイデア。入力がファイルからリダイレクトされた場合、次のプログラムはそれを再度読み取ります。(そして、stdinが端末の場合、通常、seekは何もしませんよね?)そのままにしておきます。
アレクシス

うん、できた。-何度も使うのがかわいいと思った。:)
ミケル
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.