OS / 경로 형식에 상관없이 경로에서 파일 이름 추출


794

운영 체제 또는 경로 형식에 관계없이 경로에서 파일 이름을 추출하기 위해 어떤 Python 라이브러리를 사용할 수 있습니까?

예를 들어, 나는이 모든 경로가 나를 돌려주기를 원합니다 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모듈 (Windows에서 실행할 때 os.path와 동일)은 모든 플랫폼에서 모든 (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) 한 가지주의 사항이 있습니다. Linux 파일 이름 에는 백 슬래시가 포함될 수 있습니다 . 따라서 Linux에서는 r'a/b\c'항상 폴더 의 파일 b\c을 참조하고 aWindows에서는 항상cb 폴더의 하위 폴더에있는 파일을a 합니다. 앞뒤 슬래시가 경로에 사용하는 경우 그래서, 당신은 필요 올바르게 해석 할 수 있도록 관련 플랫폼을 알고. 실제로 Linux 파일 이름에는 백 슬래시가 거의 사용되지 않으므로 일반적으로 Windows 경로라고 가정하는 것이 안전하지만 코드를 작성할 때이 점을 명심하여 실수로 보안 허점을 만들지 마십시오.


29
Windows에서는 모듈을 내부적으로 os.path로드합니다 ntpath. 이 모듈을 사용하면 '\\'Linux 시스템에서도 경로 구분 기호 를 처리 할 수 ​​있습니다 . Linux의 경우 posixpath모듈 (resp. os.path)은 posix 스타일 '/'구분 기호 만 허용하도록 경로 조작을 단순화합니다 .
moooeeeep

@moooeeeep 그래서 Stranac의 답변을 사용할 수 있으며 신뢰할 수 있습니까? ( "다른 사람들이 제안한 것처럼 os.path.split 또는 os.path.basename을 사용하는 것이 모든 경우에 작동하지는 않습니다. Linux에서 스크립트를 실행 중이고 고전적인 Windows 스타일 경로를 처리하려고하면 실패합니다" - -인용문은 Lauritz의 게시물에서 가져온 것입니다.이 경고가 Stranac의 답변과 관련이 있는지 이해하지 못합니다.)
john cj

3
@ johnc.j. r'C:\path\to\file.txt'Linux 시스템에서 Windows 스타일 경로 (예 :) 를 구문 분석해야하는 경우에만 ntpath 모듈을 사용해야합니다. 그렇지 않으면 os.path의 기능을 사용할 수 있습니다. Linux 시스템은 일반적으로 파일 이름에 백 슬래시 문자를 사용할 수 있기 때문입니다 (답변에 설명 된대로).
moooeeeep

2
귀하의 솔루션과 같지 os.path.basename(os.path.normpath(path))않습니까?
Mr_and_Mrs_D

2
이 질문에 대한 미래의 방문자에게 가치가있는 것에 대해, 나는 Lauritz가 경고하는 상황에 부딪 쳤으며 그의 해결책은 효과가있는 유일한 솔루션이었습니다. os를 사용한 핀치 링은 파일 이름 만 출력 할 수 없습니다. 그래서 imho, ntpath는 갈 길입니다.
Harabeck

1250

실제로 원하는 것을 정확하게 반환 하는 함수 가 있습니다.

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

22
OS 독립적 인 방법으로 경로를 처리하려면 os.path.basename (u "C : \\ temp \\ bla.txt")의 경우 'bla.txt'가 표시됩니다. 문제는 유효한 파일 이름을 얻는 것이 아니라 경로 이름을 추출하는 것입니다.
Adi Roiban

3
경로의 파일 이름을 찾는 Google 검색 에서이 답변이 가장 도움이되었습니다. 내 유스 케이스는 Windows에만 있습니다.
Bobort

2
os.path.basename(your_path)이것은 효과가 있었다! 스크립트 경로 : os.path.dirname(os.path.realpath(__file__))및 스크립트 이름 :을 원했습니다 os.path.basename(os.path.realpath(__file__)). 감사!
TheWalkingData

@AdiRoiban 당신의 의견을 정교하게 설명해 주시겠습니까? Windows 7에서 테스트 한 결과 실제로 "bla.txt"가 표시됩니다. 간단히 말해서, 어떤 문제도 보이지 않습니다.
john cj

10
@ johnc.j. 요점은 Linux에서 이것을 시도했을 때 'C:\\temp\\bla.txt'대신 얻을 수 있다는 것입니다.
moooeeeep

218

os.path.split 은 당신이 찾고있는 기능입니다

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

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

40
다른 사용자가주의를 기울일 수 있도록 경로가 "/"또는 "\"로 끝나는 경우 ""를 반환합니다.
BuZz

내가하려고하면 "C : \ 사용자 \ 델 \ 바탕 화면 \ ProjectShadow \ 버튼 \ button.py을"이 반환 생 "ProjectShadow utton tton"는 올바른 결과를 반환이 아닌 다른 모든 것을
amitnair92

4
@ amitnair92-이 작업을 수행하십시오 : r "C : \ Users \ Dell \ Desktop \ ProjectShadow \ button \ button.py"또는 다음 : "C : \\ Users \\ Dell \\ Desktop \\ ProjectShadow \\ button \\ button .py "-"\ b "는 \ r 또는 \ n이 줄 바꿈 / 캐리지 리턴을 나타내는 방식과 비슷한 특수 문자 (시스템 '종'이라고 생각합니다)입니다. R와 문자열 접두어 : "C를 \ ..."수단은 주어진 원료 입력 사용
브루스 Lamond

87

파이썬 3에서

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

사용하는 pathlib 항목에 따라 3.4-3.6 이상
LightCC

8
또한 Path ( "some / path / to / file.dat"). stem을 사용하여 파일 확장자가없는 파일 이름을 얻을 수 있습니다
s2t2

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

tail은 원하는 파일 이름입니다.

자세한 내용은 Python OS 모듈 문서 를 참조하십시오


13
다른 사용자가주의를 기울일 수 있도록 경로가 "/"또는 "\"로 끝나는 경우 ""를 반환합니다.
BuZz

18
import os
file_location = '/srv/volume1/data/eds/eds_report.csv'
file_name = os.path.basename(file_location )  #eds_report.csv
location = os.path.dirname(file_location )    #/srv/volume1/data/eds

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정답을 제공 했다고 생각 합니다. 내 코드는 유닉스 시스템의 Windows와 같은 경로와 Windows 시스템의 유닉스와 같은 경로에서 작동하지 않습니다.


귀하의 답변은 r"a\b\c"Linux 또는 "a/b/c"Windows 에서는 작동하지 않습니다 .
Lauritz V. Thaulow

물론, 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/")""인해 반환 됩니다.
Lauritz V. Thaulow

lazyr당신이 맞아요! 나는 그것에 대해 생각하지 않았다. 그냥하는 것이 안전할까요 path = path.replace('\\', '/')?
스키

@Skirmantas 나는 생각하지만, 옳지 않다. 경로 처리는 작업을 위해 만들어진 내장 도구로 수행해야한다고 생각합니다. 거기에 많이 더 눈에 보이는 것보다 경로로는.
Lauritz V. Thaulow

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

이것은 반환됩니다 : paint.exe

경로 또는 OS와 관련하여 split 함수의 sep 값을 변경하십시오.


이것이 내가 좋아하는 대답이지만 왜 다음을 수행하지 않습니까? 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]))

그러나 일반적으로 Windows 경로에서 찾을 수있는 "\"로 경로가 분산되면 다음 코드를 사용할 수 있습니다

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]))

OS 유형을 확인하여 하나의 함수로 결합하여 결과를 반환 할 수 있습니다.


7

이것은 표준 라이브러리와 함께 Linux 및 Windows에서 작동합니다.

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

다음은 정규식 전용 솔루션이며 모든 OS의 모든 OS 경로에서 작동하는 것 같습니다.

다른 모듈이 필요하지 않으며 사전 처리가 필요하지 않습니다.

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/dir 등 c:\windows\) 정규식을 다음으로 변경하십시오 r'[^\\/]+(?![\\/])$'. "regex challengeed"의 경우, 이것은 슬래시 에 대한 포지티브 포워드 룩어 헤드를 네거티브 포워드 룩어 헤드로 변경하여, 슬래시 로 끝나는 경로명이 경로명 의 마지막 하위 디렉토리 대신 아무것도 반환하지 않도록합니다. 물론 잠재적 인 파일 이름이 실제로 파일을 나타내 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

정규식은 여기에서 테스트 할 수 있습니다 .


당신은 re, 왜 os 모듈을 사용하고 있습니까?
Saurabh Chandra Patel

@SaurabhChandraPatel 그것은 오래되었습니다. 올바르게 기억한다면이 경우 정규 표현식이 크로스 플랫폼 솔루션으로 사용됩니다. 예를 들어 Linux 서버에서 Windows 파일 이름을 처리 할 수 ​​있습니다.
Eric Duminil

5

어쩌면 중요하지 않은 하나의 솔루션으로 내 모든 것을 어쩌면 (임시 파일을 만드는 임시 파일 : D)

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

의 값을 얻는 것은 abc.name이 같은 문자열이 될 것이다 : '/tmp/tmpks5oksk7' 나는 교체 할 수 있도록 /공백으로 .replace("/", " ")다음 호출split() . 그러면 목록이 반환되고 목록의 마지막 요소가[-1]

모듈을 가져올 필요가 없습니다.


2
파일 이름이나 디렉토리에 공백이 있으면 어떻게됩니까?
kriss

1
직접 분할 ( "/") [-1]은 어떻습니까?
Nan

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))

그것들은 더블 백 슬레이가 아닙니다. 이들은 단일 백 슬래시이므로 이스케이프해야합니다.
Eric Duminil 2016 년

3

Windows 구분 기호는 Unix 파일 이름 또는 Windows 경로에있을 수 있습니다. Unix 구분 기호는 Unix 경로에만 존재할 수 있습니다. Unix 구분 기호가 있으면 Windows가 아닌 경로를 나타냅니다.

다음은 OS 특정 구분 기호로 잘라 내기 구분 기호를 제거한 다음 가장 오른쪽 값을 나누고 반환합니다. 추악하지만 위의 가정에 따라 간단합니다. 가정이 올바르지 않은 경우 업데이트하십시오.보다 정확한 조건에 맞게이 응답을 업데이트하겠습니다.

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

완벽을 기하기 위해 다음은 pathlibPython 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']

이것은 Windows와 Linux 모두에서 작동합니다.


1

Python 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있습니다. 이것이 작동하지 않는 경우을 사용하여 Windows 경로를 강제로 인식 할 수 있습니다 fromwinpath=True. 이것은 입력 문자열을 여러 부분으로 나눕니다. 마지막은 찾고있는 잎 path2unix(t)[-1]입니다.

인수 nojoin=False인 경우 경로가 다시 결합되므로 출력은 단순히 Unix 형식으로 변환 된 입력 문자열이므로 플랫폼 간 하위 경로를 비교하는 데 유용 할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.