2012-12-31 19 views
14

लगता है मैं समझ गए होंगे कि कैसे कॉल() का उपयोग करने के लिए एक कमांड को चलाने के लिए मेरी अजगर स्क्रिप्ट प्राप्त करने के लिए:अजगर, उपप्रक्रिया, कॉल(), check_call और returncode अगर एक कमांड मौजूद

import subprocess 

mycommandline = ['lumberjack', '-sleep all night', '-work all day'] 
subprocess.call(mycommandline) 

यह काम करता है लेकिन एक समस्या है, क्या होगा यदि उपयोगकर्ताओं के पास उनके कमांड पथ में lumberjack नहीं है? यह काम करेगा अगर lumberjack को उसी निर्देशिका में पाइथन लिपि के रूप में रखा गया था, लेकिन स्क्रिप्ट को कैसे पता चलेगा कि इसे लकड़ी के टुकड़े की तलाश करनी चाहिए? मुझे लगा कि अगर कोई कमांड नहीं मिला है तो lumberjack कमांड पथ में नहीं होगा, स्क्रिप्ट यह पता लगाने की कोशिश कर सकती है कि इसकी निर्देशिका क्या है और वहां लंबरजैक की तलाश है और आखिर में उपयोगकर्ता को लंबरजैक को कॉपी करने के लिए चेतावनी दी उन दो स्थानों पर अगर यह किसी एक में नहीं मिला था। मैं कैसे पता लगा सकता हूं कि त्रुटि संदेश क्या है? मैंने पढ़ा है कि check_call() एक त्रुटि संदेश और रिटर्नकोड विशेषता के बारे में कुछ वापस कर सकता है। मुझे check_call() और रिटर्नकोड का उपयोग करने के तरीके पर उदाहरण नहीं मिल सका, संदेश क्या होगा या मैं कैसे बता सकता हूं कि संदेश कमांड नहीं मिला है या नहीं।

क्या मैं भी इस बारे में सही तरीके से जा रहा हूं?

+2

'check_call()' अगर कोई आदेश साफ से बाहर नहीं निकलता है (जो मौजूदा अस्तित्वों की अपेक्षा की जाती है) – inspectorG4dget

+3

भी, मैं उपयोगकर्ता को निष्पादन योग्य प्रतिलिपि बनाने के लिए कहने की सलाह नहीं दूंगा, अंतिम उपाय के अलावा । पैकेज मैनेजर सामान स्थापित करने के लिए लगभग हमेशा सबसे अच्छा विकल्प हैं। –

+1

@ डेवब्रंकर: आप 'कॉल' बनाम 'चेक_call' के बारे में थोड़ा उलझन में लगते हैं। 'कॉल' पहले से ही आपको रिटर्न कोड देता है-एक विशेषता के रूप में नहीं, जैसे फ़ंक्शन का रिटर्न वैल्यू। 'Check_call' का उपयोग करने का कारण यह है कि यह आपके लिए उस वापसी कोड की जांच करने का ख्याल रखता है, जिसे 'कॉलडप्रोसेसर' उठाया जाता है। कार्यक्रम के लिए कोई भी आपको 'ओएसआरआरआर' (या इसी तरह, आपके पायथन संस्करण के आधार पर) उठाता है। – abarnert

उत्तर

2

वाह, यह तेजी से गया था!

import os, sys, subprocess 

def nameandpath(): 
    try: 
     subprocess.call([os.getcwd() + '/lumberjack']) 
     # change the word lumberjack on the line above to get an error 
    except OSError: 
     print('\nCould not find lumberjack, please reinstall.\n') 
     # if you're using python 2.x, change the() to spaces on the line above 

try: 
    subprocess.call(['lumberjack']) 
    # change the word lumberjack on the line above to get an error 
except OSError: 
    nameandpath() 

मैं मैक ओएस एक्स (6.8/Snow Leopard), डेबियन (निचोड़) पर यह परीक्षण किया है और: मैं Theodros Zelleke के सरल उदाहरण और चलती फ़ाइलों के बारे में OSError और Lattyware की टिप्पणी के बारे में abarnert टिप्पणी के साथ कार्यों की steveha के उपयोग संयुक्त विंडोज 7)। ऐसा लगता है कि मैं इसे तीनों ऑपरेटिंग सिस्टमों पर करना चाहता था। मैंने check_call और CalledProcessError का उपयोग करने का प्रयास किया लेकिन इससे कोई फर्क नहीं पड़ता कि मैंने क्या किया, मुझे हर बार एक त्रुटि मिलती थी और मुझे त्रुटियों को संभालने के लिए स्क्रिप्ट नहीं मिल सका। स्क्रिप्ट का परीक्षण करने के लिए मैंने 'lumberjack' से 'deadparrot' नाम बदल दिया, क्योंकि मेरे पास मेरी स्क्रिप्ट के साथ निर्देशिका में lumberjack था।

क्या आपको इस लिपि के साथ किसी भी समस्या को लिखा गया है?

4

subprocess कोई आदेश नहीं मिलने पर OSError अपवाद उठाएगा।

जब आदेश मिलता है, और subprocess आपके लिए आदेश चलाता है, तो परिणाम कोड आदेश से वापस कर दिया जाता है। मानक यह है कि कोड 0 का अर्थ सफलता है, और कोई विफलता कुछ गैर-शून्य त्रुटि कोड है (जो भिन्न होती है; आपके द्वारा चलाए जा रहे विशिष्ट आदेश के लिए दस्तावेज़ देखें)।

तो, यदि आप OSError पकड़ते हैं तो आप गैर-मौजूद कमांड को संभाल सकते हैं, और यदि आप परिणाम कोड जांच सकते हैं तो आप यह पता लगा सकते हैं कि आदेश सफल हुआ या नहीं।

बड़ी बात के बारे में subprocess है कि आप इसे stdout और stderr से सभी पाठ इकट्ठा कर सकते हैं, और आप तो इसे त्यागने कर सकते हैं या इसे वापस या यह प्रवेश करें या इसे प्रदर्शित के रूप में आप की तरह है। मैं अक्सर एक रैपर का उपयोग करता हूं जो कमांड से सभी आउटपुट को त्याग देता है, जब तक कि आदेश stderr से पाठ आउटपुट में विफल रहता है।

मैं मानता हूं कि आपको उपयोगकर्ताओं को निष्पादन योग्य प्रतिलिपि बनाने के लिए नहीं कहना चाहिए। कार्यक्रम PATH चर में सूचीबद्ध निर्देशिका में होना चाहिए; यदि कोई प्रोग्राम गुम है, तो इसे स्थापित किया जाना चाहिए, या यदि यह PATH पर निर्देशिका में स्थापित नहीं है, तो उपयोगकर्ता को उस निर्देशिका को शामिल करने के लिए PATH अद्यतन करना चाहिए।

ध्यान दें कि आप निष्पादनयोग्य के लिए विभिन्न हार्ड-कोडेड पथ के साथ subprocess कई बार प्रयास करने का विकल्प है:

import os 
import subprocess as sp 

def _run_cmd(s_cmd, tup_args): 
    lst_cmd = [s_cmd] 
    lst_cmd.extend(tup_args) 
    result = sp.call(lst_cmd) 
    return result 

def run_lumberjack(*tup_args): 
    try: 
     # try to run from /usr/local/bin 
     return _run_cmd("/usr/local/bin/lumberjack", tup_args) 
    except OSError: 
     pass 

    try: 
     # try to run from /opt/forest/bin 
     return _run_cmd("/opt/forest/bin/lumberjack", tup_args) 
    except OSError: 
     pass 

    try: 
     # try to run from "bin" directory in user's home directory 
     home = os.getenv("HOME", ".") 
     s_cmd = home + "/bin/lumberjack" 
     return _run_cmd(s_cmd, tup_args) 
    except OSError: 
     pass 

    # Python 3.x syntax for raising an exception 
    # for Python 2.x, use: raise OSError, "could not find lumberjack in the standard places" 
    raise OSError("could not find lumberjack in the standard places") 

run_lumberjack("-j") 

संपादित करें: इसके बारे में एक छोटा सा सोच के बाद, मैं पूरी तरह से ऊपर फिर से लिखने का फैसला किया। बस स्थानों की एक सूची पास करने के लिए यह बहुत साफ है, और जब तक कोई काम नहीं करता तब तक लूप वैकल्पिक स्थानों को आज़माएं। लेकिन अगर उपयोगकर्ता की जरूरत नहीं थी, तो मैं उपयोगकर्ता की होम निर्देशिका के लिए स्ट्रिंग बनाना नहीं चाहता था, इसलिए मैंने विकल्पों की सूची में कॉल करने योग्य बना दिया। यदि इसके बारे में आपके कोई प्रश्न हैं, तो बस पूछें।

import os 
import subprocess as sp 

def try_alternatives(cmd, locations, args): 
    """ 
    Try to run a command that might be in any one of multiple locations. 

    Takes a single string argument for the command to run, a sequence 
    of locations, and a sequence of arguments to the command. Tries 
    to run the command in each location, in order, until the command 
    is found (does not raise OSError on the attempt). 
    """ 
    # build a list to pass to subprocess 
    lst_cmd = [None] # dummy arg to reserve position 0 in the list 
    lst_cmd.extend(args) # arguments come after position 0 

    for path in locations: 
     # It's legal to put a callable in the list of locations. 
     # When this happens, we should call it and use its return 
     # value for the path. It should always return a string. 
     if callable(path): 
      path = path() 

     # put full pathname of cmd into position 0 of list  
     lst_cmd[0] = os.path.join(path, cmd) 
     try: 
      return sp.call(lst_cmd) 
     except OSError: 
      pass 
    raise OSError('command "{}" not found in locations list'.format(cmd)) 

def _home_bin(): 
    home = os.getenv("HOME", ".") 
    return os.path.join(home, "bin") 

def run_lumberjack(*args): 
    locations = [ 
     "/usr/local/bin", 
     "/opt/forest/bin", 
     _home_bin, # specify callable that returns user's home directory 
    ] 
    return try_alternatives("lumberjack", locations, args) 

run_lumberjack("-j") 
19

एक सरल टुकड़ा:

try: 
    subprocess.check_call(['executable']) 
except subprocess.CalledProcessError: 
    pass # handle errors in the called executable 
except OSError: 
    pass # executable not found 
संबंधित मुद्दे