কীভাবে বর্তমান স্ক্রিপ্ট ডিরেক্টরিটি সঠিকভাবে নির্ধারণ করবেন?


260

আমি দেখতে চাই পাইথনের বর্তমান স্ক্রিপ্ট ডিরেক্টরিটি নির্ধারণের সেরা উপায় কোনটি?

আমি আবিষ্কার করেছি যে অজগর কোড কল করার বিভিন্ন উপায়ের কারণে, ভাল সমাধান খুঁজে পাওয়া শক্ত।

এখানে কিছু সমস্যা রয়েছে:

  • __file__স্ক্রিপ্টটি দিয়ে সম্পাদিত হলে সংজ্ঞায়িত হয় না exec,execfile
  • __module__ শুধুমাত্র মডিউলগুলিতে সংজ্ঞায়িত করা হয়

ব্যবহারের ক্ষেত্রে:

  • ./myfile.py
  • python myfile.py
  • ./somedir/myfile.py
  • python somedir/myfile.py
  • execfile('myfile.py') (অন্য স্ক্রিপ্ট থেকে, এটি অন্য ডিরেক্টরিতে অবস্থিত হতে পারে এবং এতে আরও একটি বর্তমান ডিরেক্টরি থাকতে পারে।

আমি জানি যে এর কোনও নিখুঁত সমাধান নেই, তবে আমি সেরা পদ্ধতির সন্ধান করছি যা বেশিরভাগ ক্ষেত্রে সমাধান করে।

সর্বাধিক ব্যবহৃত পদ্ধতির os.path.dirname(os.path.abspath(__file__))তবে আপনি যদি অন্য কোনওর সাথে স্ক্রিপ্টটি সম্পাদন করেন তবে এটি সত্যিই কাজ করে না exec()

সতর্কতা

যে ডিরেক্টরিটি বর্তমান ডিরেক্টরি ব্যবহার করে তা ব্যর্থ হবে, স্ক্রিপ্টটি যেভাবে বলা হয় তার উপর ভিত্তি করে এটি চলমান স্ক্রিপ্টের অভ্যন্তরে পরিবর্তিত হতে পারে different


1
ফাইলটি কোথা থেকে এসেছে তা আপনি কী আরও সুনির্দিষ্ট করতে পারেন? - ফাইলটি আমদানি করা কোডগুলিতে (সচেতন হোস্ট অন্তর্ভুক্ত) বা ফাইলটি আমদানি করা যায়? (স্ব-সচেতন দাস)
সিনথেসাইজারপ্যাটেল

3
আপনি pathlibঅজগর ৩.৪ বা তার বেশি ব্যবহার করলে রন কালিয়ান এর সমাধানটি দেখুন : stackoverflow.com/a/48931294/1011724
ড্যান

সুতরাং সমাধানটি কোডের কোনও বর্তমান ডিরেক্টরি ব্যবহার করা নয়, তবে কিছু কনফিগার ফাইল ব্যবহার করার জন্য?
ZhaoGang

আকর্ষণীয় আবিষ্কার, আমি সবেমাত্র করেছি: python myfile.pyশেল থেকে কাজ করার সময় এটি কাজ করে, তবে ভিএম এর মধ্যে :!python %এবং উভয়ই ব্যর্থ হয় সিস্টেমটি নির্দিষ্ট পথটি খুঁজে পায় না। এটি বেশ বিরক্তিকর। এই এবং সম্ভাব্য কর্মক্ষেত্রের পিছনে কারণ সম্পর্কে কেউ মন্তব্য করতে পারেন? :!python myfile.py
ইনভেডার

উত্তর:


231
os.path.dirname(os.path.abspath(__file__))

আপনি পেতে যাচ্ছেন সত্যিই সেরা।

exec/ দিয়ে স্ক্রিপ্ট সম্পাদন করা অস্বাভাবিক execfile; সাধারণত আপনার স্ক্রিপ্টগুলি লোড করতে মডিউল অবকাঠামো ব্যবহার করা উচিত। আপনি এই পদ্ধতি ব্যবহার করা আবশ্যক, তবে আমি সেটিং সুপারিশ __file__মধ্যে globalsস্ক্রিপ্টটি পাস তাই এটি যে ফাইলের নাম পড়তে পারেন।

ছাড় দেওয়া কোডে ফাইলের নাম পাওয়ার আর কোনও উপায় নেই: যেমন আপনি নোট করেছেন, সিডাব্লুডি সম্পূর্ণ ভিন্ন জায়গায় থাকতে পারে।


2
কখনও না বল না? এর মতে: stackoverflow.com/a/18489147 উত্তর একটি ক্রস প্ল্যাটফর্ম সমাধান abspath হয় (গেটসোফ্রিল (ল্যাম্বদা: 0))? নাকি আমি আর কিছু মিস করছি?
জেফ এলেন

131

আপনি যদি সত্যই কোনও স্ক্রিপ্টের মাধ্যমে ডেকে পাঠানো মামলাটি কভার করতে চান তবে আপনি ফাইলের নাম (পথ সহ) কেটে নেওয়ার জন্য মডিউলটি execfile(...)ব্যবহার করতে পারেন inspect। আমি যতদূর জানি, এটি আপনার তালিকাভুক্ত সমস্ত মামলার জন্য কাজ করবে:

filename = inspect.getframeinfo(inspect.currentframe()).filename
path = os.path.dirname(os.path.abspath(filename))

4
আমি মনে করি এটি প্রকৃতপক্ষে সবচেয়ে শক্তিশালী পদ্ধতি, তবে আমি এর জন্য ওপি'র বর্ণিত প্রয়োজনীয়তা নিয়ে প্রশ্ন করি। আমি প্রায়শই দেখি যে বিকাশকারীরা যখন এক্সিকিউটিভ মডিউলটির তুলনায় লোকেশনগুলিতে ডেটা ফাইল ব্যবহার করেন তবে আইএমও ডেটা ফাইলগুলি একটি পরিচিত স্থানে রাখা উচিত।
রায়ান জিনস্ট্রোম

14
@ রায়ান এলওএল, আপনি যদি এমন একটি "পরিচিত অবস্থান" সংজ্ঞায়িত করতে সক্ষম হন যে মাল্টিপ্লাটফর্ম এবং এটি মডিউলটি নিয়ে আসে তবে দুর্দান্ত। আমি বাজি রাখতে প্রস্তুত যে একমাত্র নিরাপদ অবস্থান হ'ল স্ক্রিপ্টের অবস্থান। দ্রষ্টব্য, এই স্ক্রিপ্টটি এই অবস্থানটিতে লেখা উচিত নয়, তবে ডেটা পড়ার জন্য এটি নিরাপদ।
sorin

1
তবুও, সমাধানটি ভাল নয়, কেবল chdir()ফাংশনের আগে কল করার চেষ্টা করুন , এটি ফলাফল পরিবর্তন করবে। অন্য ডিরেক্টরি থেকে পাইথন স্ক্রিপ্ট কল করলে ফলাফল পরিবর্তন হবে, সুতরাং এটি ভাল সমাধান নয়।
sorin

2
os.path.expanduser("~")ব্যবহারকারীর ডিরেক্টরি পাওয়ার একটি ক্রস প্ল্যাটফর্ম উপায়। দুর্ভাগ্যক্রমে, অ্যাপ্লিকেশন ডেটা কোথায় আটকাতে হবে এটি উইন্ডোজ সেরা অভ্যাস নয়।
রায়ান জিনস্ট্রোম

6
@ সোরিন: আমি chdir()স্ক্রিপ্ট চালানোর আগে চেষ্টা করেছি ; এটি সঠিক ফলাফল উত্পাদন করে। আমি অন্য ডিরেক্টরি থেকে স্ক্রিপ্ট কল করার চেষ্টা করেছি এবং এটি কাজ করে। ফলাফল একই inspect.getabsfile()ভিত্তিযুক্ত সমাধান
jfs

43
#!/usr/bin/env python
import inspect
import os
import sys

def get_script_dir(follow_symlinks=True):
    if getattr(sys, 'frozen', False): # py2exe, PyInstaller, cx_Freeze
        path = os.path.abspath(sys.executable)
    else:
        path = inspect.getabsfile(get_script_dir)
    if follow_symlinks:
        path = os.path.realpath(path)
    return os.path.dirname(path)

print(get_script_dir())

এটি সিপিথন, জাইথন, পাইপিতে কাজ করে। স্ক্রিপ্টটি ব্যবহার করে কার্যকর করা হলে এটি কাজ করে execfile()( sys.argv[0]এবং- __file__ভিত্তিক সমাধানগুলি এখানে ব্যর্থ হবে)। স্ক্রিপ্টটি এক্সিকিউটেবল জিপ ফাইলের (/ একটি ডিম) ভিতরে থাকলে এটি কাজ করে । স্ক্রিপ্টটি PYTHONPATH=/path/to/library.zip python -mscript_to_runএকটি জিপ ফাইল থেকে "আমদানি" করা হয় তবে এটি কাজ করে ; এটি এক্ষেত্রে সংরক্ষণাগারটি ফেরত দেয়। স্ক্রিপ্টটি স্বতন্ত্র এক্সিকিউটেবল ( sys.frozen) এ সংকলন করা থাকলে এটি কাজ করে । এটি সিমলিংকের জন্য কাজ করে ( realpathপ্রতীকী লিঙ্কগুলি সরিয়ে দেয়)। এটি একটি ইন্টারেক্টিভ ইন্টারপ্রেটারে কাজ করে; এটি এক্ষেত্রে বর্তমান ওয়ার্কিং ডিরেক্টরিটি প্রদান করে।


পাইআইনস্টলারের সাথে পুরোপুরি ভাল কাজ করে।
চমত্কার

1
ডকুমেন্টেশনেgetabsfile(..) উল্লেখ না করারinspect কোনও কারণ আছে কি ? এটি সেই পৃষ্ঠায় লিঙ্কযুক্ত উত্সে উপস্থিত হয়।
এভেজেনি সার্জিভ

@ এভেজেনি সার্জিভ এটি একটি বাগ হতে পারে। এটি চারপাশে একটি সাধারণ মোড়ক getsourcefile(), getfile()যা নথিভুক্ত।
jfs

24

পাইথন ৩.৪++ এ আপনি সহজ pathlibমডিউলটি ব্যবহার করতে পারেন :

from inspect import currentframe, getframeinfo
from pathlib import Path

filename = getframeinfo(currentframe()).filename
parent = Path(filename).resolve().parent

2
দুর্দান্ত সরলতা!
কমেটসং

3
আপনি সম্ভবত ব্যবহার করতে পারেন Path(__file__)( inspectমডিউলটির প্রয়োজন নেই )।
পেক

@ পেউক ক্রিয়াকলাপ যা প্যারেন্ট ডিরেক্টরি নয়, বর্তমান ফাইলের নাম সহ একটি পথ তৈরি করে। যদি আমি একই ডিরেক্টরিতে কোনও ফাইলের দিকে ইঙ্গিত করার জন্য যদি বর্তমান স্ক্রিপ্ট ডিরেক্টরিটি পেতে চেষ্টা করি যেমন স্ক্রিপ্ট হিসাবে একই ডিরেক্টরিতে একটি কনফিগার ফাইল লোড করার প্রত্যাশা, যখন ওপি পেতে চেয়েছিল তখন Path(__file__)দেয়/path/to/script/currentscript.py/path/to/script/
দাভোস

8
ওহ আমি ভুল বুঝেছি, আপনি অর্থাত্ পরিদর্শন মডিউলটি এড়িয়ে চলতে চাইছেন এবং কিছুটা ভালো ব্যবহার করুন parent = Path(__file__).resolve().parent That's
দাভোস

3
@ ডট এ। আপনার .joinpath()(বা /অপারেটর) এর জন্য ব্যবহার করা উচিত , না +
ইউজিন ইয়ারম্যাশ

13

os.path...পাইথন 2- এ অ্যাপ্রোচটি ছিল 'সম্পন্ন জিনিস'।

পাইথন 3 এ, আপনি স্ক্রিপ্টের ডিরেক্টরিটি নীচের মতো দেখতে পাবেন:

from pathlib import Path
cwd = Path(__file__).parents[0]

11
বা ঠিক Path(__file__).parent। তবে cwdএটি একটি মিসনোমার, এটি এখনকার চলমান ডিরেক্টরি নয় , তবে ফাইলের ডিরেক্টরি । তারা একই হতে পারে, তবে সাধারণত এটি হয় না।
নুনো আন্দ্রে

5

কেবল os.path.dirname(os.path.abspath(__file__))যেখানে execব্যবহৃত হয়েছে সেখানে আসল প্রয়োজন আছে কিনা তা খুব সাবধানে ব্যবহার করুন এবং পরীক্ষা করুন । আপনি মডিউল হিসাবে আপনার স্ক্রিপ্টটি ব্যবহার করতে সক্ষম না হলে এটি ঝামেলা নকশার লক্ষণ হতে পারে।

পাইথন # 8 এর জেন মনে রাখবেন , এবং আপনি যদি বিশ্বাস করেন যে কোনও ব্যবহারের ক্ষেত্রে এটির জন্য কার্যকর হওয়া উচিত execতবে এটির জন্য অবশ্যই কাজ করা উচিত তবে দয়া করে আমাদের সমস্যার পটভূমি সম্পর্কে আরও কিছু বিশদ জানান know


2
যদি আপনি এক্সিকিউটিভ () দিয়ে না চলে থাকেন তবে আপনি ডিবাগার প্রসঙ্গটি আলগা করবেন। এছাড়াও এক্সিকিউটিভ () নতুন প্রক্রিয়া শুরু করার চেয়ে যথেষ্ট দ্রুত হবে বলে মনে করা হচ্ছে।
sorin

@ সোরিন এটি একটি এক্সিকিউটিভ বনাম একটি নতুন প্রক্রিয়া শুরু করার প্রশ্ন নয়, সুতরাং এটি স্ট্রোম্যান যুক্তি। এটি আমদানি বা ফাংশন কল ব্যবহার করে বনামের বনামের প্রশ্ন question
wim

4

হায়

import os
cwd = os.getcwd()

যা ইচ্ছে কর? "বর্তমান স্ক্রিপ্ট ডিরেক্টরি" বলতে আপনাকে ঠিক কী বোঝাতে চাইছি তা আমি নিশ্চিত নই। আপনার দেওয়া ব্যবহারের ক্ষেত্রে প্রত্যাশিত আউটপুটটি কী হবে?


3
এটি সাহায্য করবে না। আমি বিশ্বাস করি @ কলগান কল স্ট্যাকের শীর্ষে থাকা স্ক্রিপ্টের জন্য ডিরেক্টরিটি সন্ধান করছেন। উদাহরণস্বরূপ, তার / তার সমস্ত ক্ষেত্রে এটি 'মাইফিল.পি' বসেছে এমন ডিরেক্টরি মুদ্রণ করা উচিত। এখনও আপনার পদ্ধতি শুধু তাই কল ফাইলের ডিরেক্টরি প্রিন্ট হবে exec('myfile.py'), যেমন একই __file__এবং sys.argv[0]
ঝাং 18

হ্যাঁ, এটা বোঝা যায়। আমি কেবল এটি নিশ্চিত করতে চেয়েছিলাম যে @ বোগদান কোনও সাধারণ বিষয় উপেক্ষা করছেন না এবং তারা কী চান তা আমি ঠিক বলতে পারি না।
ম্যাককুচেন

3

প্রথম .. যদি আমরা বেনামী কোড ইনজেক্ট করার উপায়গুলির বিষয়ে কথা বলছি তবে এখানে একটি দম্পতি ব্যবহারের ক্ষেত্রে অনুপস্থিত ..

code.compile_command()
code.interact()
imp.load_compiled()
imp.load_dynamic()
imp.load_module()
__builtin__.compile()
loading C compiled shared objects? example: _socket?)

তবে, আসল প্রশ্নটি হল, আপনার লক্ষ্যটি কী - আপনি কোনও ধরণের সুরক্ষা প্রয়োগের চেষ্টা করছেন? বা আপনি কী বোঝাচ্ছেন তাতে কেবল আগ্রহী?

আপনি আগ্রহী হন, তাহলে নিরাপত্তা , ফাইলের নাম যে মাধ্যমে আমদানি করা হচ্ছে Exec / execfile হয় তুচ্ছ - আপনি ব্যবহার করা উচিত rexec , যা অফার করুন:

এই মডিউলটিতে আরএক্সেক ক্লাস রয়েছে, যা r_eval (), r_execfile (), r_exec (), এবং r_import () পদ্ধতিগুলিকে সমর্থন করে, যা স্ট্যান্ডার্ড পাইথন ফাংশনগুলি eval (), execfile () এবং এক্সিকিউট এবং আমদানির বিবৃতিগুলির সীমাবদ্ধ সংস্করণ। এই সীমাবদ্ধ পরিবেশে কার্যকর করা কোডের কেবলমাত্র মডিউল এবং ফাংশনগুলিতে অ্যাক্সেস থাকবে যা নিরাপদ বলে মনে করা হয়; আপনি আরএক্সকে সাবক্লাস করতে পারেন পছন্দসই ক্ষমতা যুক্ত করতে বা মুছে ফেলতে।

যাইহোক, যদি এটি আরও একাডেমিক অনুসারী হয় .. তবে এখানে কয়েকটি দম্পতি বুদ্ধিমান পন্থা রয়েছে যা আপনি সম্ভবত আরও গভীরভাবে খনন করতে সক্ষম হবেন ..

স্ক্রিপ্ট উদাহরণ:

./deep.py

print ' >> level 1'
execfile('deeper.py')
print ' << level 1'

./deeper.py

print '\t >> level 2'
exec("import sys; sys.path.append('/tmp'); import deepest")
print '\t << level 2'

/tmp/deepest.py

print '\t\t >> level 3'
print '\t\t\t I can see the earths core.'
print '\t\t << level 3'

./codespy.py

import sys, os

def overseer(frame, event, arg):
    print "loaded(%s)" % os.path.abspath(frame.f_code.co_filename)

sys.settrace(overseer)
execfile("deep.py")
sys.exit(0)

আউটপুট

loaded(/Users/synthesizerpatel/deep.py)
>> level 1
loaded(/Users/synthesizerpatel/deeper.py)
    >> level 2
loaded(/Users/synthesizerpatel/<string>)
loaded(/tmp/deepest.py)
        >> level 3
            I can see the earths core.
        << level 3
    << level 2
<< level 1

অবশ্যই এটি এটি করার একটি উত্স-নিবিড় উপায়, আপনি আপনার সমস্ত কোডটি সন্ধান করছেন .. খুব দক্ষ না Not তবে, আমি মনে করি এটি একটি অভিনব দৃষ্টিভঙ্গি যেহেতু আপনি নীড়ের গভীরে getুকে যাওয়ার পরেও এটি কাজ করে চলেছে। আপনি 'ইভাল' ওভাররাইড করতে পারবেন না। যদিও আপনি এক্সিকিফাইল () কে ওভাররাইড করতে পারেন

দ্রষ্টব্য, এই পদ্ধতির কেবল 'আমদানি' নয়, এক্সিকিউটিভ / এক্সিকিউটিফিলকে কভার করে। উচ্চ স্তরের 'মডিউল' লোড হুকিংয়ের জন্য আপনি ব্যবহার করতে পারবেন sys.path_hooks ( পাইমোটডাব্লু সৌজন্যে রচনা আপ)।

আমার মাথার উপরের অংশটি ছেড়ে দেওয়া সমস্ত কিছু।


2

এখানে একটি আংশিক সমাধান, এখনও পর্যন্ত প্রকাশিত সকলের চেয়ে ভাল better

import sys, os, os.path, inspect

#os.chdir("..")

if '__file__' not in locals():
    __file__ = inspect.getframeinfo(inspect.currentframe())[0]

print os.path.dirname(os.path.abspath(__file__))

এখন এই কাজগুলি সমস্ত কল করবে কিন্তু কেউ যদি chdir()বর্তমান ডিরেক্টরি পরিবর্তন করতে ব্যবহার করে তবে এটি ব্যর্থ হবে।

মন্তব্য:

  • sys.argv[0]কাজ করছে না, আপনি -cযদি স্ক্রিপ্টটি সম্পাদন করেন তবে ফিরে আসবেpython -c "execfile('path-tester.py')"
  • আমি https://gist.github.com/1385555 এ একটি সম্পূর্ণ পরীক্ষা প্রকাশ করেছি এবং এটি উন্নত করতে আপনাকে স্বাগতম।

1

এটি বেশিরভাগ ক্ষেত্রে কাজ করা উচিত:

import os,sys
dirname=os.path.dirname(os.path.realpath(sys.argv[0]))

5
এই সমাধানটি বর্তমান ডিরেক্টরি ব্যবহার করে এবং এটি স্পষ্টভাবে প্রশ্নে বলা হয়েছে যে এই জাতীয় সমাধান ব্যর্থ হবে।
আকাশ ছোঁয়াচ্ছে

1

আশা করি এটি সহায়তা করে: - আপনি যদি যে কোনও জায়গা থেকে স্ক্রিপ্ট / মডিউল চালান তবে আপনি স্ক্রিপ্টটির __file__অবস্থানের প্রতিনিধিত্বকারী মডিউল ভেরিয়েবলটি অ্যাক্সেস করতে সক্ষম হবেন ।

অন্যদিকে, আপনি যদি দোভাষীটি ব্যবহার করেন তবে আপনার সেই ভেরিয়েবলটিতে অ্যাক্সেস নেই, যেখানে আপনি একটি নাম পাবেন NameErrorএবং os.getcwd()আপনি অন্য কোথাও থেকে ফাইলটি চালনা করলে আপনাকে ভুল ডিরেক্টরি দেবে।

এই সমাধানটি আপনাকে দেওয়া উচিত যা আপনি সব ক্ষেত্রে সন্ধান করছেন:

from inspect import getsourcefile
from os.path import abspath
abspath(getsourcefile(lambda:0))

আমি এটি পুরোপুরি পরীক্ষা করে দেখিনি তবে এটি আমার সমস্যার সমাধান করেছে।


এটি ফাইলটি দেবে, ডিরেক্টরি নয়
শীতল শাহ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.