পাইথন: স্ক্রিপ্টগুলির কার্যকারী ডিরেক্টরিটি স্ক্রিপ্টের নিজস্ব ডিরেক্টরিতে পরিবর্তন করুন Change


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__"হিমায়িত" প্রোগ্রামগুলিতে ব্যর্থ হয় (পাইপেক্স, পাইআইন্সটলার, সিএক্স_ফ্রিজে ব্যবহার করে তৈরি করা হয়েছে)। sys.argv[0]কাজ করে। @ ক্রিসডাউন: আপনি যদি সিমলিংকগুলি অনুসরণ করতে চান; os.path.realpath()ব্যবহৃত হতে পারে.
jfs

3
@ এলিকোর্টউইরাইট যদি __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
এস। লট ঠিক আছে। ডেটা ট্রানজিটরি না হলে ডেটা এবং কোড সর্বদা আলাদা রাখুন। উদাহরণস্বরূপ, যদি আপনার আইকন থাকে তবে তা ডেটা, তবে এটি ট্রানজিটরি নয়, এবং এটি সফ্টওয়্যার বান্ডেলের সাথে সম্পর্কিত বিবেচনা করে বিবেচ্য হবে (যার অর্থ যাই হোক না কেন)
স্টেফানো বোরিনি

5
@ উদি প্যাসমন: মোটেও সুদূর নয়। এটি "ছোট রক্ষণাবেক্ষণের স্ক্রিপ্টগুলি" যা সংস্থাগুলি গভীর সমস্যায় পড়ে। আজ থেকে কয়েক বছর ধরে, এই "ছোট রক্ষণাবেক্ষণ স্ক্রিপ্ট" এবং এটি শিশু এবং ডেরাইভেশন এবং ডেটা ফাইলগুলি বিভক্ত করা এবং পুনরায় সংশোধন করার জন্য একটি দুঃস্বপ্ন হবে। যতটা সম্ভব কোড থেকে ডেটা রাখুন - সমস্ত কিছুর জন্য প্যারামিটারগুলি পাস করুন - কিছুই অনুমান করুন।
এস .লট

1
+1 আমি ভেবেছিলাম আমি ওপি হিসাবে করতে চাই, তবে আপনার পরামর্শ পড়ার পরে আমি আমার স্ক্রিপ্টটি পরিবর্তিত করেছি। লগ ফাইলের অবস্থান নির্দিষ্ট করার জন্য এখন এটির জন্য একটি প্যারামিটার প্রয়োজন।
আইয়েন স্যামুয়েল ম্যাকলিন বয়স্ক

+1 টি। ডেটা ডিরেক্টরিগুলি সহজে কাস্টমাইজ করা যায় তবে পাইথন স্ক্রিপ্টের জন্য একটি প্যাকেজ (আরপিএম) তৈরি করা সহজ।
jfs

18

আপনার ক্রোনটব আদেশটি এতে পরিবর্তন করুন

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

(...)একটি একক কমান্ড হিসাবে আপনার crond, executes একটি উপ-শেল শুরু হয়। || exit 1ক্ষেত্রে ব্যর্থ ডিরেক্টরিটি অনুপলব্ধ আপনার cronjob ঘটায়।

যদিও আপনার নির্দিষ্ট স্ক্রিপ্টগুলির জন্য অন্যান্য সমাধানগুলি দীর্ঘমেয়াদে আরও মার্জিত হতে পারে তবে আমার উদাহরণ এখনও সেই ক্ষেত্রে কার্যকর হতে পারে যেখানে আপনি প্রোগ্রাম বা কমান্ডটি সম্পাদন করতে পারবেন না যা আপনি চালাতে চান।


1
এটি একটি অত্যন্ত শব্দ সমাধান। আমি সাধারণত নিজের মতো করে অন্যান্য লোকদের উত্তর সম্পাদনা করে দেখতে পাই || exit 1। এটি দেখতে সতেজ হয়। যদিও আমাকে ভাবতে হবে যে আপনি কেন করবেন নাcd /home/udi/foo/ && ./bar.py
ব্রুনো ব্রোনোস্কি

2
@ ব্রুনো ব্রোনোস্কি স্পষ্টতই exit 1আপনার ক্রন্ডকে একটি ত্রুটি সম্পর্কে অবহিত করা হবে এবং বেশিরভাগ ক্ষেত্রে ব্যর্থতার একটি ইমেল বিজ্ঞপ্তি প্রেরণ করবে।
রউদ আলথুইজেন
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.