파이썬 프로그램을 적절한 유닉스 도구처럼 동작하게하려면 어떻게해야합니까?


24

몇 가지 Python 스크립트가 있으며 다시 작성하려고합니다. 나는 그들 모두와 같은 문제가 있습니다.

적절한 유닉스 도구처럼 동작하도록 프로그램을 작성하는 방법은 분명하지 않습니다.

왜냐하면 이건

$ cat characters | progname

$ progname characters

동일한 출력을 생성해야합니다.

파이썬에서 찾을 수있는 가장 가까운 것은 파일 입력 라이브러리였습니다. 불행히도 파이썬 스크립트를 다시 작성하는 방법을 실제로 보지 못합니다. 모두 다음과 같습니다.

#!/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하드 코드 된 파일 경로보다 이식성이 뛰어 나기 때문에 대신 사용해야합니다.
Piotr Dobrogost

sys.stdinPiotr이 말했듯이 대신 사용해야합니다
smci

그러나 sys.stdin파일이며 이미 열려 있으므로 닫혀서는 안됩니다. 후프를 뛰어 넘지 않고 파일 인수 처럼 처리 할 수 없습니다.
알렉시스

@alexis Sure, 닫거나 f컨텍스트 관리자를 사용하려면 더 복잡한 것이 필요합니다. 대안으로 내 새로운 답변을 참조하십시오.
Mikel

12

파일 이름이 인수로 제공되는지 확인하거나에서 읽습니다 sys.stdin.

이 같은:

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

sys모듈을 사용한다는 점을 제외하면 Mikel의 답변과 비슷 합니다. 나는 그들이 거기에 있다면 그것이 이유가 있어야한다고 생각합니다 ...


명령 행에 두 개의 파일 이름이 지정된 경우 어떻게됩니까?
Mikel

3
아 절대적으로! 이미 답변에 표시되어 있기 때문에 표시하지 않았습니다. 어떤 시점에서 사용자가 필요한 것을 결정하도록 사용자를 신뢰해야합니다. 그러나 이것이 가장 좋다고 생각되면 자유롭게 편집하십시오. 내 요점은로만 교체 "open(/dev/stdin")하는 것 sys.stdin입니다.
rahmu

2
그렇지 않으면 if len(sys.argv)>1:대신 확인하고 싶을 수도 있습니다. if sys.argv[1]:범위를 벗어난 색인 오류가 발생했습니다
Yibo Yang

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 필터의 철학에 맞지 않습니다.
musiphil

isatty사마귀 외에 , 이것은 다른 답변에서 찾을 수없는 유용하고 중요한 근거를 다루므로 내 의견을 얻습니다.
tripleee

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모든 시스템에서 사용할 수없는 경우이 방법으로 작성했을 것 입니다.
Mikel

0

이 솔루션을 사용하고 있으며 매력처럼 작동합니다. 실제로 나는 주어진 문자열에서 소문자를 제거하고 악센트를 제거 하는 스크립트 calle unaccent 를 사용 하고 있습니다.

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이 터미널이라면 보통 아무것도 찾지 마십시오.) 그냥 두십시오.
알렉시스

그래 방금 -여러 번 사용하는 것이 귀엽다고 생각했습니다 . :)
Mikel
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.