पथ से फ़ाइल नाम निकालें, कोई फर्क नहीं पड़ता कि ओएस / पथ प्रारूप क्या है


794

पायथन लाइब्रेरी को मैं पथ से फ़ाइल नाम निकालने के लिए उपयोग कर सकता हूं, कोई फर्क नहीं पड़ता कि ऑपरेटिंग सिस्टम या पथ प्रारूप क्या हो सकता है?

उदाहरण के लिए, मैं चाहूंगा कि ये सभी रास्ते मुझे लौटा दें c:

a/b/c/
a/b/c
\a\b\c
\a\b\c\
a\b\c
a/b/../../a/b/c/
a/b/../../a/b/c

जवाबों:


781

अन्य मामलों में उपयोग os.path.splitया os.path.basenameसुझाव देने से काम नहीं चलेगा: यदि आप लिनक्स पर स्क्रिप्ट चला रहे हैं और क्लासिक विंडो-स्टाइल पथ को संसाधित करने का प्रयास कर रहे हैं, तो यह विफल हो जाएगा।

Windows पथ पथ विभाजक के रूप में बैकस्लैश या फ़ॉरवर्ड स्लैश का उपयोग कर सकते हैं। इसलिए, ntpathमॉड्यूल (जो विंडोज़ पर चलने के दौरान ओएस के बराबर है । ) सभी प्लेटफार्मों पर सभी (1) पथों के लिए काम करेगा ।

import ntpath
ntpath.basename("a/b/c")

बेशक, यदि फ़ाइल एक स्लैश के साथ समाप्त होती है, तो बेसन खाली हो जाएगा, इसलिए इससे निपटने के लिए अपना स्वयं का कार्य करें:

def path_leaf(path):
    head, tail = ntpath.split(path)
    return tail or ntpath.basename(head)

सत्यापन:

>>> paths = ['a/b/c/', 'a/b/c', '\\a\\b\\c', '\\a\\b\\c\\', 'a\\b\\c', 
...     'a/b/../../a/b/c/', 'a/b/../../a/b/c']
>>> [path_leaf(path) for path in paths]
['c', 'c', 'c', 'c', 'c', 'c', 'c']


(1) एक चेतावनी है: लिनक्स फ़ाइलनाम में बैकस्लैश हो सकते हैं । इसलिए लिनक्स पर, r'a/b\c'हमेशा फ़ोल्डर b\cमें फ़ाइल को संदर्भित करता है a, जबकि विंडोज पर, यह हमेशा फ़ोल्डर cके bसबफ़ोल्डर में फ़ाइल को संदर्भित करता है a। तो जब दोनों आगे और पीछे स्लैश एक पथ में उपयोग किया जाता है, तो आप की जरूरत संबद्ध मंच पता करने के लिए इसे सही ढंग से व्याख्या करने के लिए सक्षम होने के लिए। व्यवहार में यह आम तौर पर यह मान लेना सुरक्षित है कि बैकस्लैश लिनक्स फाइलनाम में उपयोग किए जाने के बाद से यह एक विंडोज़ पथ है, लेकिन इसे ध्यान में रखें जब आप कोड बनाते हैं तो आप आकस्मिक सुरक्षा छेद नहीं बनाते हैं।


29
विंडोज पर, os.pathबस ntpathमॉड्यूल को आंतरिक रूप से लोड करता है । इस मॉड्यूल का उपयोग करके, '\\'लिनक्स मशीनों पर भी पथ विभाजकों को संभालना संभव है । लिनक्स के लिए posixpathमॉड्यूल (रिस्पांस os.path) केवल पॉज़िक्स स्टाइल '/'सेपरेटर की अनुमति देने के लिए पथ संचालन को सरल करेगा ।
मूओईपिप

@mooeeeeeep तो हम स्ट्रैन्क के उत्तर का उपयोग कर सकते हैं, और यह विश्वसनीय है? ( "Os.path.split या os.path.basename का उपयोग करना) जैसा कि दूसरों का सुझाव है कि सभी मामलों में काम नहीं करेगा: यदि आप लिनक्स पर स्क्रिप्ट चला रहे हैं और क्लासिक विंडो-स्टाइल पथ को संसाधित करने का प्रयास करते हैं, तो यह विफल हो जाएगा" - - यह उद्धरण लॉरिट्ज़ की पोस्ट से है - और मुझे समझ में नहीं आता है, क्या यह चेतावनी स्ट्रैन्क के उत्तर की चिंता करती है, या नहीं)।
जॉन सीजे

3
@ johnc.j। केवल जब आपको r'C:\path\to\file.txt'लिनक्स मशीन पर विंडोज स्टाइल पथ (जैसे ) पार्स करने की आवश्यकता होती है , तो आपको एनपीटीपी मॉड्यूल का उपयोग करने की आवश्यकता होती है। अन्यथा, आप os.path से फ़ंक्शन का उपयोग कर सकते हैं। ऐसा इसलिए है क्योंकि लिनक्स सिस्टम आमतौर पर फ़ाइल नाम में बैकस्लैश पात्रों के उपयोग की अनुमति देता है (जैसा कि उत्तर में समझाया गया है)।
मूओइपिप

2
आपके समाधान के बराबर नहीं है os.path.basename(os.path.normpath(path))?
Mr_and_Mrs_D

2
इस सवाल के लिए आने वाले आगंतुकों के लिए क्या मूल्य है, मैं उस स्थिति में भाग गया जब लॉरिट्ज के बारे में चेतावनी दे रहा था और उसका समाधान केवल एक ही काम था। ओएस के साथ कोई फाइनेंगलिंग सिर्फ फ़ाइल नाम का उत्पादन नहीं कर सका। तो इम्हो, ntpath जाने का रास्ता है।
हरबेक

1250

दरअसल, एक ऐसा फंक्शन है, जो वास्तव में आप चाहते हैं

import os
print(os.path.basename(your_path))

22
यदि आप OS को स्वतंत्र तरीके से पथ संसाधित करना चाहते हैं, तो os.path.basename (u "C: \\ temp \\ bla.txt") के लिए आप 'bla.txt' प्राप्त करने की अपेक्षा कर रहे हैं। सवाल वैध फ़ाइल नाम प्राप्त करने का नहीं है, बल्कि एक पथ के लिए नाम निकालने का है।
आदि रोयबन

3
एक पथ का फ़ाइल नाम खोजने के लिए मेरे Google खोज पर, यह उत्तर सबसे उपयोगी था। मेरा उपयोग मामला वैसे भी केवल विंडोज पर है।
बोबोर्ट नोव

2
os.path.basename(your_path)यह काम किया! मुझे स्क्रिप्ट का रास्ता चाहिए था: os.path.dirname(os.path.realpath(__file__))और स्क्रिप्ट का नाम os.path.basename(os.path.realpath(__file__)):। धन्यवाद!
TheWalkingData

@AdiRoiban क्या आप कृपया अपनी टिप्पणी विस्तृत कर सकते हैं? मैंने इसे विंडोज 7 पर टेस्ट किया और मुझे वास्तव में "bla.txt 'मिला। बस यह कहते हुए, मुझे कोई समस्या नहीं दिख रही है (खुद के लिए)।
जॉन सीजे

10
@ johnc.j। बिंदु यह है, जब आपने लिनक्स पर यह प्रयास किया था, तो आप 'C:\\temp\\bla.txt'इसके बजाय प्राप्त करेंगे ।
मूओइपिप

218

os.path.split वह फ़ंक्शन है जिसे आप खोज रहे हैं

head, tail = os.path.split("/tmp/d/a.dat")

>>> print(tail)
a.dat
>>> print(head)
/tmp/d

40
अन्य उपयोगकर्ताओं को सावधान रहने के लिए, यह रिटर्न "" यदि पथ "/" या "\" में समाप्त होता है
BuZz

जब मैं "C: \ Users \ Dell \ Desktop \ ProjectShadow \ बटन \ बटन" आज़माता हूं, तो यह "ProjectShadow utton tton" देता है, इसके अलावा अन्य सभी चीज़ों के लिए यह सही परिणाम देता है
amitnair92

4
@ amitnair92 - या तो ऐसा करें: r "C: \ Users \ Dell \ Desktop \ ProjectShadow \ बटन \ button.py" या यह: "C: \\ Users \\ Dell \\ Desktop \\ ProjectShadow \\ \\ बटन .py "-" \ b "एक विशेष वर्ण (सिस्टम 'बेल' है जो मुझे लगता है), newline / carriage रिटर्न को how \ r या \ n के समान है। R "C: \ ..." के साथ स्ट्रिंग को प्रीफ़िक्स करने का अर्थ है दिए गए कच्चे इनपुट का उपयोग करें
ब्रूस लैमोंड

87

अजगर में ३

>>> from pathlib import Path    
>>> Path("/tmp/d/a.dat").name
'a.dat'

३.४ से ३.६ या बाद में, बिल्कुल आपके द्वारा उपयोग किए जाने वाले पैथलिब आइटम पर निर्भर करता है।
लाइटसीसी

8
पथ ("कुछ / पथ / से / file.dat") का भी उपयोग कर सकते हैं। फ़ाइल एक्सटेंशन के बिना फ़ाइल नाम प्राप्त करने के लिए स्टेम
222 पर s2t2

47
import os
head, tail = os.path.split('path/to/file.exe')

पूंछ जो आप चाहते हैं, फ़ाइल नाम।

विस्तार के लिए अजगर ओएस मॉड्यूल डॉक्स देखें


13
अन्य उपयोगकर्ताओं को सावधान रहने के लिए, यह रिटर्न "" यदि पथ "/" या "\" में समाप्त होता है
BuZz


12

अपने उदाहरण में आपको दाहिनी ओर से वापस लौटने के लिए स्लैश भी उतारना होगा c:

>>> import os
>>> path = 'a/b/c/'
>>> path = path.rstrip(os.sep) # strip the slash from the right side
>>> os.path.basename(path)
'c'

दूसरा स्तर:

>>> os.path.filename(os.path.dirname(path))
'b'

अद्यतन: मुझे लगता lazyrहै कि सही उत्तर दिया है। मेरा कोड यूनिक्स सिस्टम पर विंडोज़ जैसे रास्तों के साथ काम नहीं करेगा और विन्डोज़ सिस्टम पर यूनिक्स जैसे रास्तों के साथ।


आपका जवाब न तो r"a\b\c"लिनक्स पर काम करेगा , न ही "a/b/c"खिड़कियों पर।
लॉरिट्ज वी। थुलो

ज़ाहिर है, os.path.basename(path)केवल तभी काम करेंगे os.path.isfile(path)है True। इसलिए path = 'a/b/c/'एक वैध फ़ाइल नाम नहीं है ...
moooeeeep

1
@fmaas os.path.basename विशुद्ध रूप से एक स्ट्रिंग-प्रोसेसिंग फ़ंक्शन है। यह परवाह नहीं करता है कि फाइल मौजूद है या नहीं, यह फाइल है या डिर। os.path.basename("a/b/c/")रिटर्न ""स्लैश की वजह से।
लॉरिट्ज़ वी। थुलो 12

lazyrतुम सही हो! मैंने इसके बारे में नहीं सोचा था। क्या यह सिर्फ करना सुरक्षित होगा path = path.replace('\\', '/')?
स्की 12

@Skirmantas मुझे लगता है, लेकिन यह सही नहीं लगता है। मुझे लगता है कि नौकरी के लिए बनाए गए उपकरणों के साथ पथ प्रसंस्करण किया जाना चाहिए। नहीं है एक बहुत अधिक रास्तों को उससे कहीं।
लॉरिट्ज़ वी। थुलो

11
fname = str("C:\Windows\paint.exe").split('\\')[-1:][0]

यह वापस आएगा: पेंट। exe

अपने पथ या OS के बारे में विभाजन फ़ंक्शन के सेप मूल्य को बदलें।


यह उत्तर मुझे पसंद है, लेकिन सिर्फ निम्नलिखित क्यों नहीं? fname = str(path).split('/')[-1]
asultan904

10

यदि आप फ़ाइल नाम अपने आप प्राप्त करना चाहते हैं तो आप कर सकते हैं

import glob

for f in glob.glob('/your/path/*'):
    print(os.path.split(f)[-1])

8

यदि आपका फ़ाइल पथ "/" से समाप्त नहीं हुआ है और निर्देशिका "/" से अलग हो गई है तो निम्न कोड का उपयोग करें। जैसा कि हम जानते हैं कि आम तौर पर पथ "/" के साथ समाप्त नहीं होता है।

import os
path_str = "/var/www/index.html"
print(os.path.basename(path_str))

लेकिन कुछ मामलों में जैसे URL "/" के साथ समाप्त होते हैं, फिर निम्न कोड का उपयोग करते हैं

import os
path_str = "/home/some_str/last_str/"
split_path = path_str.rsplit("/",1)
print(os.path.basename(split_path[0]))

लेकिन जब आपका पथ "\" द्वारा फैलाया जाता है जिसे आप आमतौर पर विंडोज़ पथों में पाते हैं तो आप निम्नलिखित कोड का उपयोग कर सकते हैं

import os
path_str = "c:\\var\www\index.html"
print(os.path.basename(path_str))

import os
path_str = "c:\\home\some_str\last_str\\"
split_path = path_str.rsplit("\\",1)
print(os.path.basename(split_path[0]))

आप दोनों प्रकार के चेक ओएस प्रकार से जोड़ सकते हैं और परिणाम वापस कर सकते हैं।


7

यह लिनक्स और खिड़कियों के साथ-साथ मानक पुस्तकालय के लिए भी काम कर रहा है

paths = ['a/b/c/', 'a/b/c', '\\a\\b\\c', '\\a\\b\\c\\', 'a\\b\\c',
         'a/b/../../a/b/c/', 'a/b/../../a/b/c']

def path_leaf(path):
    return path.strip('/').strip('\\').split('/')[-1].split('\\')[-1]

[path_leaf(path) for path in paths]

परिणाम:

['c', 'c', 'c', 'c', 'c', 'c', 'c']

6

यहां रेगेक्स-ओनली सॉल्यूशन है, जो किसी भी ओएस पर किसी भी ओएस पथ के साथ काम करता है।

किसी अन्य मॉड्यूल की आवश्यकता नहीं है, और किसी भी प्रीप्रोसेसिंग की आवश्यकता नहीं है:

import re

def extract_basename(path):
  """Extracts basename of a given path. Should Work with any OS Path on any OS"""
  basename = re.search(r'[^\\/]+(?=[\\/]?$)', path)
  if basename:
    return basename.group(0)


paths = ['a/b/c/', 'a/b/c', '\\a\\b\\c', '\\a\\b\\c\\', 'a\\b\\c',
         'a/b/../../a/b/c/', 'a/b/../../a/b/c']

print([extract_basename(path) for path in paths])
# ['c', 'c', 'c', 'c', 'c', 'c', 'c']


extra_paths = ['C:\\', 'alone', '/a/space in filename', 'C:\\multi\nline']

print([extract_basename(path) for path in extra_paths])
# ['C:', 'alone', 'space in filename', 'multi\nline']

अपडेट करें:

आप केवल एक चाहते हैं संभावित फ़ाइल नाम, यदि वर्तमान (यानी, /a/b/एक निर्देशिका है और इसलिए है c:\windows\), करने के लिए regex बदलने के लिए: r'[^\\/]+(?![\\/])$'। "Regex को चुनौती दी," इस बात के लिए सकारात्मक आगे अग्रदर्शी बदलता है स्लेश किसी प्रकार का एक नकारात्मक करने के लिए तत्पर अग्रदर्शी, pathnames के कारण ही कहा साथ अंत स्लेश वापसी कुछ नहीं के बजाय पथ में पिछले उप-निर्देशिका के लिए। बेशक, इस बात की कोई गारंटी नहीं है कि संभावित फ़ाइलनाम वास्तव में एक फ़ाइल को संदर्भित करता है और इसके लिए os.path.is_dir()या os.path.is_file()उसे नियोजित करने की आवश्यकता होगी।

यह निम्नानुसार मेल करेगा:

/a/b/c/             # nothing, pathname ends with the dir 'c'
c:\windows\         # nothing, pathname ends with the dir 'windows'
c:hello.txt         # matches potential filename 'hello.txt'
~it_s_me/.bashrc    # matches potential filename '.bashrc'
c:\windows\system32 # matches potential filename 'system32', except
                    # that is obviously a dir. os.path.is_dir()
                    # should be used to tell us for sure

रेगेक्स का परीक्षण यहां किया जा सकता है


तुम फिर से उपयोग कर रहे हैं, क्यों नहीं ओएस मॉड्यूल?
सौरभ चंद्र पटेल

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

5

शायद कुछ महत्वपूर्ण के बिना एक समाधान में शायद मेरा सब कुछ (अस्थायी फ़ाइलों को बनाने के लिए अस्थायी संबंध: डी)

import tempfile
abc = tempfile.NamedTemporaryFile(dir='/tmp/')
abc.name
abc.name.replace("/", " ").split()[-1] 

मूल्यों को प्राप्त करना abc.nameइस तरह से एक स्ट्रिंग होगा: '/tmp/tmpks5oksk7' इसलिए मैं /एक स्थान के साथ बदल सकता हूं .replace("/", " ")और फिर कॉल कर सकता हूं split()। वह सूची वापस कर देगा और मुझे सूची का अंतिम तत्व मिल जाएगा[-1]

किसी भी मॉड्यूल को आयात करने की आवश्यकता नहीं है।


2
क्या होगा यदि फ़ाइलनाम या निर्देशिका में कोई स्थान है?
क्रिश

1
एक प्रत्यक्ष विभाजन ("/") [- 1] के बारे में क्या?
नान

4

मैंने कभी डबल-बैकस्लैश पथ नहीं देखे हैं, क्या वे मौजूदा हैं? अजगर मॉड्यूल की अंतर्निहित सुविधा osउन लोगों के लिए विफल रहती है। अन्य सभी काम करते हैं, आपके द्वारा दिए गए चेतावनी भी os.path.normpath():

paths = ['a/b/c/', 'a/b/c', '\\a\\b\\c', '\\a\\b\\c\\', 'a\\b\\c', 
...     'a/b/../../a/b/c/', 'a/b/../../a/b/c', 'a/./b/c', 'a\b/c']
for path in paths:
    os.path.basename(os.path.normpath(path))

वे दोहरी पीठ नहीं हैं। वे सिंगल बैकस्लैश हैं, और उन्हें भागने की जरूरत है।
एरिक डुमिनील

3

विंडोज विभाजक एक यूनिक्स फ़ाइल नाम या विंडोज पथ में हो सकता है। यूनिक्स विभाजक केवल यूनिक्स पथ में मौजूद हो सकता है। यूनिक्स विभाजक की उपस्थिति एक गैर-विंडोज पथ को इंगित करती है।

ओएस विशिष्ट विभाजक द्वारा निम्नलिखित स्ट्रिप (विभाजक विभाजक को काट देगा), फिर विभाजित होकर सही मान लौटाएगा। यह बदसूरत है, लेकिन ऊपर की धारणा के आधार पर सरल है। यदि धारणा गलत है, तो कृपया अपडेट करें और मैं इस प्रतिक्रिया को अधिक सटीक स्थितियों से मेल करने के लिए अपडेट करूंगा।

a.rstrip("\\\\" if a.count("/") == 0 else '/').split("\\\\" if a.count("/") == 0 else '/')[-1]

नमूना कोड:

b = ['a/b/c/','a/b/c','\\a\\b\\c','\\a\\b\\c\\','a\\b\\c','a/b/../../a/b/c/','a/b/../../a/b/c']

for a in b:

    print (a, a.rstrip("\\" if a.count("/") == 0 else '/').split("\\" if a.count("/") == 0 else '/')[-1])

1
इसके अलावा, मुझे इस स्थान पर प्रारूपित करने के तरीके पर संकेत भेजने के लिए स्वतंत्र महसूस करें। नमूना कोड प्राप्त करने के लिए आधा दर्जन प्रयास किए गए।
dusc2don

1

पूर्णता के लिए, यहां pathlibअजगर 3.2+ का समाधान दिया गया है :

>>> from pathlib import PureWindowsPath

>>> paths = ['a/b/c/', 'a/b/c', '\\a\\b\\c', '\\a\\b\\c\\', 'a\\b\\c', 
...          'a/b/../../a/b/c/', 'a/b/../../a/b/c']

>>> [PureWindowsPath(path).name for path in paths]
['c', 'c', 'c', 'c', 'c', 'c', 'c']

यह विंडोज और लिनक्स दोनों पर काम करता है।


1

पायथन 2 और 3 दोनों में, मॉड्यूल pathlib2 का उपयोग करते हुए :

import posixpath  # to generate unix paths
from pathlib2 import PurePath, PureWindowsPath, PurePosixPath

def path2unix(path, nojoin=True, fromwinpath=False):
    """From a path given in any format, converts to posix path format
    fromwinpath=True forces the input path to be recognized as a Windows path (useful on Unix machines to unit test Windows paths)"""
    if not path:
        return path
    if fromwinpath:
        pathparts = list(PureWindowsPath(path).parts)
    else:
        pathparts = list(PurePath(path).parts)
    if nojoin:
        return pathparts
    else:
        return posixpath.join(*pathparts)

उपयोग:

In [9]: path2unix('lala/lolo/haha.dat')
Out[9]: ['lala', 'lolo', 'haha.dat']

In [10]: path2unix(r'C:\lala/lolo/haha.dat')
Out[10]: ['C:\\', 'lala', 'lolo', 'haha.dat']

In [11]: path2unix(r'C:\lala/lolo/haha.dat') # works even with malformatted cases mixing both Windows and Linux path separators
Out[11]: ['C:\\', 'lala', 'lolo', 'haha.dat']

अपने टेस्टकेस के साथ:

In [12]: testcase = paths = ['a/b/c/', 'a/b/c', '\\a\\b\\c', '\\a\\b\\c\\', 'a\\b\\c',
    ...: ...     'a/b/../../a/b/c/', 'a/b/../../a/b/c']

In [14]: for t in testcase:
    ...:     print(path2unix(t)[-1])
    ...:
    ...:
c
c
c
c
c
c
c

यहां विचार pathlib2मंच के आधार पर सभी रास्तों को अलग-अलग डिकोडर के साथ एकीकृत आंतरिक प्रतिनिधित्व में बदलने का है। सौभाग्य से, pathlib2इसमें एक सामान्य डिकोडर शामिल है , जिसे PurePathकिसी भी पथ पर काम करना चाहिए। यदि यह काम नहीं करता है, तो आप विंडोज़ पथ के उपयोग की मान्यता को बाध्य कर सकते हैं fromwinpath=True। यह इनपुट स्ट्रिंग को भागों में विभाजित करेगा, आखिरी वह पत्ती है जिसे आप खोज रहे हैं, इसलिए path2unix(t)[-1]

यदि तर्क nojoin=False, पथ वापस जुड़ जाएगा, तो यह है कि आउटपुट बस इनपुट स्ट्रिंग को यूनिक्स प्रारूप में बदल दिया गया है, जो प्लेटफार्मों भर में सबपैथ की तुलना करने के लिए उपयोगी हो सकता है।

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