मैं पायथन कार्यक्रमों को उचित यूनिक्स उपकरणों की तरह कैसे व्यवहार करता हूं?


24

मेरे पास कुछ पायथन स्क्रिप्ट हैं, जो चारों ओर बिछी हुई हैं, और मैं उन्हें फिर से लिखने पर काम कर रहा हूं। मुझे उन सभी के साथ एक ही समस्या है।

मेरे लिए यह स्पष्ट नहीं है कि कार्यक्रम कैसे लिखें ताकि वे उचित यूनिक्स उपकरणों की तरह व्यवहार करें।

क्योंकि यह

$ 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

फ़ाइलइनपुट लाइब्रेरी स्टड को प्रोसेस करती है अगर कोई स्टडिन है, और एक फाइल होने पर एक फाइल को प्रोसेस करता है। लेकिन यह एकल लाइनों पर पुनरावृत्त करता है।

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इसके बजाय, इसका इस्तेमाल किया जाना चाहिए, जैसा कि
पियोटर

लेकिन sys.stdinएक फ़ाइल है, और यह पहले से ही खुला है, और बंद नहीं होना चाहिए। हूप्स के माध्यम से कूदने के बिना एक फ़ाइल तर्क की तरह संभालना असंभव है ।
एलेक्सिस

@alexis ज़रूर, यदि आप बंद करना चाहते हैं f, या एक संदर्भ प्रबंधक का उपयोग करना चाहते हैं, तो आपको कुछ और जटिल चाहिए। विकल्प के रूप में मेरा नया उत्तर देखें।
मिकेल

12

जाँच करें कि क्या एक फ़ाइलनाम एक तर्क के रूप में दिया गया है, या फिर से पढ़ें sys.stdin

कुछ इस तरह:

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

यह मिकेल के उत्तर के समान है सिवाय इसके कि यह sysमॉड्यूल का उपयोग करता है । मुझे लगता है कि अगर वे इसे वहाँ एक कारण के लिए होना चाहिए ...


क्या होगा यदि कमांड लाइन पर दो फ़ाइल नाम निर्दिष्ट हैं?
मिकेल

3
ओह बिल्कुल! मैंने इसे दिखाने से परेशान नहीं किया क्योंकि यह आपके उत्तर में पहले ही दिखाया जा चुका था। कुछ बिंदु पर आपको यह तय करने के लिए उपयोगकर्ता पर भरोसा करना होगा कि उसे क्या चाहिए। लेकिन अगर आपको लगता है कि यह सबसे अच्छा है तो संपादित करने के लिए स्वतंत्र महसूस करें। मेरी बात केवल "open(/dev/stdin")साथ देने की है sys.stdin
रहमू

2
आप if len(sys.argv)>1:इसके बजाय जाँच करना चाह सकते हैं if sys.argv[1]:अन्यथा आपको त्रुटि से बाहर एक सूचकांक मिलता है
Yibo Yang

3

इसे करने का मेरा पसंदीदा तरीका है ... (और यह एक अच्छा सा लिनक्स ब्लॉग से लिया गया है जिसे हर्बिंगर होल कहा जाता है )

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

मुझे यह सबसे अच्छा क्यों लगा, इसका कारण यह है, जैसा कि ब्लॉगर कहते हैं, यह सिर्फ एक मूर्खतापूर्ण संदेश देता है अगर गलती से बिना इनपुट के कॉल किया जाए। यह मेरे सभी मौजूदा पायथन लिपियों में इतनी बारीकी से स्लॉट करता है कि मैंने इसे शामिल करने के लिए उन सभी को संशोधित किया है।


3
कभी-कभी आप एक tty से अंतःक्रियात्मक रूप से इनपुट दर्ज करना चाहते हैं; चेकिंग isattyऔर बाउलिंग यूनिक्स फिल्टर के दर्शन के अनुरूप नहीं है।
मुस्लिम

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

मुझे लगता है मैं इस समाधान यहाँ था firest समय देखा ।


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

आप फ़ाइल पॉइंटर को बाहर निकलने पर क्यों हिलाते हैं? बुरा विचार। यदि इनपुट को किसी फ़ाइल से रीडायरेक्ट किया गया था, तो अगला प्रोग्राम इसे फिर से पढ़ेगा। (और अगर स्टड एक टर्मिनल है, तो आमतौर पर कुछ भी नहीं चाहिए, ठीक है?) बस इसे अकेला छोड़ दें।
एलेक्सिस

हाँ, किया। मुझे लगा कि यह -कई बार उपयोग करने के लिए प्यारा था । :)
मिकेल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.