अजगर: स्क्रिप्ट को काम करने वाली डायरेक्टरी को स्क्रिप्ट की अपनी डायरेक्टरी में बदलें


171

मैं हर मिनट में क्रेस्टब से एक अजगर खोल चलाता हूं:

* * * * * /home/udi/foo/bar.py

/home/udi/fooकुछ आवश्यक उपनिर्देशिकाएं हैं, जैसे /home/udi/foo/logऔर /home/udi/foo/config, जो /home/udi/foo/bar.pyसंदर्भित करता है।

समस्या यह है कि crontabस्क्रिप्ट को एक अलग कार्यशील निर्देशिका से चलाता है, इसलिए ./log/bar.logविफल होने की कोशिश करता है।

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

संपादित करें:

os.chdir(os.path.dirname(sys.argv[0]))

सबसे कॉम्पैक्ट सुरुचिपूर्ण समाधान था। आपके उत्तर और स्पष्टीकरण के लिए धन्यवाद!


से संबंधित नहीं crontabयूज-केस: दोनों sys.argv[0]और __file__असफल हो स्क्रिप्ट का उपयोग कर चलाया जाता है execfile(); बजाय inspectसमाधान का उपयोग किया जा सकता है।
jfs

जवाबों:


206

यह आपकी वर्तमान कार्यशील निर्देशिका को बदल देगा ताकि सापेक्ष पथ खुल जाएं:

import os
os.chdir("/home/udi/foo")

हालाँकि, आपने पूछा कि आपकी पाइथन लिपि जो भी डायरेक्टरी में है, उसे कैसे बदला जाए, भले ही आपको यह न पता हो कि जब आप अपनी लिपि लिख रहे हों तो वह कौन सी डायरेक्टरी होगी। ऐसा करने के लिए, आप os.pathकार्यों का उपयोग कर सकते हैं :

import os

abspath = os.path.abspath(__file__)
dname = os.path.dirname(abspath)
os.chdir(dname)

यह आपकी स्क्रिप्ट का फ़ाइल नाम लेता है, इसे एक पूर्ण पथ में परिवर्तित करता है, फिर उस पथ की निर्देशिका को निकालता है, फिर उस निर्देशिका में परिवर्तित होता है।


3
निर्देशिका हार्डकोडिंग के बराबर है।
इक्के

2
यदि आप इसे एक सिमलिंक से चला रहे हैं, तो यह काम नहीं करेगा। के __file__बजाय का उपयोग करें sys.argv[0]
क्रिस डाउन

1
अबस्पात कदम क्यों? बस क्यों नहीं os.chdir(os.path.dirname(__file__))?
कर्नल पैनिक

8
__file__"जमे हुए" कार्यक्रमों में विफल रहता है (py2exe, PyInstaller, cx_Freeze का उपयोग करके बनाया गया)। sys.argv[0]काम करता है। @ क्रिसडाउन: यदि आप सिमिलिंक का पालन करना चाहते हैं; os.path.realpath()इस्तेमाल किया जा सकता है।
jfs

3
@EliCourtwright यदि __file__पहले से ही एक पूर्ण पथ नहीं है, और उपयोगकर्ता ने कार्यशील निर्देशिका को बदल दिया है, तो os.path.abspathवैसे भी विफल हो जाएगा।
आर्थर टाका

45

आप उपयोग करके एक छोटा संस्करण प्राप्त कर सकते हैं sys.path[0]

os.chdir(sys.path[0])

से http://docs.python.org/library/sys.html#sys.path

प्रोग्राम स्टार्टअप पर आरंभिक रूप से, इस सूची का पहला आइटम path[0], वह निर्देशिका है जिसमें स्क्रिप्ट शामिल है जिसका उपयोग पायथन इंटरप्रेटर को लागू करने के लिए किया गया था


23

यह मत करो।

आपकी स्क्रिप्ट और आपके डेटा को एक बड़ी निर्देशिका में मैश नहीं किया जाना चाहिए। कुछ ज्ञात स्थान (में अपने कोड रखो site-packagesया /var/opt/udiया कुछ और) आपके डेटा से अलग। अपने कोड पर अच्छे संस्करण नियंत्रण का उपयोग करें यह सुनिश्चित करने के लिए कि आपके पास वर्तमान और पिछले संस्करण एक दूसरे से अलग हैं ताकि आप पिछले संस्करणों पर वापस गिर सकें और अन्य संस्करणों का परीक्षण कर सकें।

नीचे पंक्ति: कोड और डेटा को न करें।

डेटा कीमती है। कोड आता है और चला जाता है।

कमांड-लाइन तर्क मान के रूप में कार्यशील निर्देशिका प्रदान करें। आप पर्यावरण चर के रूप में एक डिफ़ॉल्ट प्रदान कर सकते हैं। इसे कम मत करो (या उस पर अनुमान लगाओ)

इसे एक आवश्यक तर्क मान बनाएं और ऐसा करें।

import sys
import os
working= os.environ.get("WORKING_DIRECTORY","/some/default")
if len(sys.argv) > 1: working = sys.argv[1]
os.chdir( working )

अपने सॉफ़्टवेयर के स्थान के आधार पर निर्देशिका को "ग्रहण" न करें। यह लंबे समय में अच्छी तरह से काम नहीं करेगा।


9
मुझे लगता है कि आप बड़े सॉफ्टवेयर पैकेजों के लिए कोड और डेटा को अलग करने के बारे में सही हैं, लेकिन यह एक छोटे रखरखाव स्क्रिप्ट के लिए काफी दूर की कौड़ी लगती है। मैं पूरी तरह से संस्करण नियंत्रण के बारे में सहमत हूं।
एडम मैटन

3
S. Lott सही है। डेटा और कोड को हमेशा अलग रखें, जब तक कि डेटा क्षणभंगुर न हो। उदाहरण के लिए, यदि आपके पास आइकन हैं, तो वह डेटा है, लेकिन यह क्षणभंगुर नहीं है, और यह सॉफ्टवेयर बंडल के सापेक्ष विचार करने के लिए समझ में आता है (जो भी इसका मतलब है)
स्टेफानो बोरीनी

5
@ यूडी पासमोन: बिल्कुल भी दूर नहीं। यह "छोटी रखरखाव स्क्रिप्ट" है जो संगठनों को गहरी परेशानी में डालती है। अब से साल, यह "छोटी रखरखाव स्क्रिप्ट" और यह बच्चों और व्युत्पत्तियों और डेटा फ़ाइलों को नापसंद और पुन: लागू करने के लिए एक बुरा सपना होगा। जहां तक ​​संभव हो कोड से डेटा रखें - सब कुछ के लिए पैरामीटर पास करें - कुछ भी नहीं मानें।
S.Lott

1
+1 मैंने सोचा कि मैं ओपी के रूप में करना चाहता हूं, लेकिन आपकी सलाह पढ़ने के बाद मैंने इसके बजाय अपनी स्क्रिप्ट को संशोधित किया। अब लॉग फ़ाइल के स्थान को निर्दिष्ट करने के लिए एक पैरामीटर की आवश्यकता होती है।
इयान सैमुअल मैकलीन एल्डर

+1। एक अजगर स्क्रिप्ट के लिए एक पैकेज (आरपीएम) बनाना आसान है अगर डेटा निर्देशिकाओं को आसानी से अनुकूलित किया जा सकता है।
20:14

18

अपने crontab कमांड को बदलें

* * * * * (cd /home/udi/foo/ || exit 1; ./bar.py)

(...)कि एक ही आदेश के रूप में अपने crond कार्यान्वित एक उप खोल शुरू होता है। || exit 1आपके क्रोनजोब के विफल होने का कारण बनता है कि निर्देशिका अनुपलब्ध है।

यद्यपि आपकी विशिष्ट लिपियों के लिए लंबे समय में अन्य समाधान अधिक सुरुचिपूर्ण हो सकते हैं, मेरा उदाहरण अभी भी उन मामलों में उपयोगी हो सकता है जहां आप उस प्रोग्राम या कमांड को संशोधित नहीं कर सकते हैं जिसे आप निष्पादित करना चाहते हैं।


1
यह एक अत्यंत ध्वनि समाधान है। मैं आमतौर पर अपने आप को अन्य लोगों के उत्तर संपादित करता हूं जैसे कि चीजों को जोड़ने के लिए || exit 1। यह देखना ताज़ा है। हालांकि मुझे आश्चर्य है कि आप बस क्यों नहीं करेंगेcd /home/udi/foo/ && ./bar.py
ब्रूनो ब्रोंस्की

2
@BrunoBronosky स्पष्ट रूप से exit 1आपके क्रोन को एक त्रुटि के बारे में सूचित किया जाएगा, और ज्यादातर मामलों में विफलता की एक ईमेल सूचना भेजेगा।
रूड अल्थुइज़न
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.