os / path形式に関係なく、パスからファイル名を抽出します


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他の人が提案するように使用しても、すべてのケースで機能するわけではありません。Linuxでスクリプトを実行していて、クラシックなWindowsスタイルのパスを処理しようとすると、失敗します。

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)注意点が1つあります。Linuxファイル名にはバックスラッシュが含まれている可能性があります。したがって、Linuxではr'a/b\c'常にフォルダー内のファイルb\cを参照し、aWindowsでは常にフォルダーのサブフォルダーc内のファイルを参照します。したがって、パスでスラッシュとバックスラッシュの両方が使用されている場合、関連するプラットフォームを正しく解釈できるようにする必要があります。実際には、Linuxのファイル名ではバックスラッシュがほとんど使用されないため、Windowsパスであると想定しても安全ですが、誤ってセキュリティホールを作成しないようにコーディングするときは、このことに注意してください。ba


29
Windowsでは、モジュールを内部的にos.pathロードするだけntpathです。このモジュールを使用すると'\\'、Linuxマシンでもパス区切り文字を処理できます。Linuxの場合、posixpathモジュール(またはos.path)はパス操作を単純化して、posixスタイルの'/'セパレータのみを許可します。
moooeeeep

@moooeeeepでは、Stranacの回答を使用できますが、信頼できますか。(「他の人が示唆するようにos.path.splitまたはos.path.basenameを使用しても、すべてのケースで機能するわけではありません。Linuxでスクリプトを実行していて、クラシックなWindowsスタイルのパスを処理しようとすると、失敗します。」 - -引用はラウリッツの投稿からです-そして、私は理解していません、この警告はStranacの答えに関係するのか、そうではありません)。
john cj 2017

3
@ johnc.j。r'C:\path\to\file.txt'LinuxマシンでWindowsスタイルのパス(例:)を解析する必要がある場合のみ、ntpathモ​​ジュールを使用する必要があります。それ以外の場合は、os.pathの関数を使用できます。これは、Linuxシステムでは通常、(回答で説明されているように)ファイル名にバックスラッシュ文字を使用できるためです。
moooeeeep 2017

2
あなたの解決策は同等os.path.basename(os.path.normpath(path))ですか?
Mr_and_Mrs_D 2017年

2
この質問への将来の訪問者にとって価値があることについて、私はラウリッツが警告している状況に出くわしました、そして彼の解決策が機能した唯一のものでした。osを使った調整では、ファイル名だけを出力することはできません。だから私見、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、2014年

3
パスのファイル名を見つけるための私のGoogle検索では、この回答が最も役に立ちました。私のユースケースはとにかくWindowsでのみです。
Bobort 2016年

2
os.path.basename(your_path)これはうまくいきました!スクリプトパス:os.path.dirname(os.path.realpath(__file__))とスクリプト名:が必要os.path.basename(os.path.realpath(__file__))でした。ありがとう!
TheWalkingData 2017

@AdiRoibanコメントについて詳しく教えてください。私はWindows 7でテストしましたが、実際には「bla.txt」が表示されます。簡単に言うと、問題はありません(私自身)
john cj

10
@ johnc.j。ポイントは、Linuxでこれを試みたときに、'C:\\temp\\bla.txt'代わりに取得することです。
moooeeeep 2017

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 \ button \ 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:\ ..."を
付けると

87

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

尾はあなたが望むもの、ファイル名です。

詳細については、Python OSモジュールのドキュメントをご覧ください


13
他のユーザーが注意するために、パスが「/」または「\」で終わっている場合、これは「」を返します
BuZz

19
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は正しい答えを提供したと思います。私のコードは、UNIXシステムのWindowsのようなパスでは機能せず、逆に、WindowsシステムのUNIXのようなパスでも機能しません。


あなたの答えは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に関する分割関数の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タイプをチェックして結果を返すことで、両方を1つの関数に結合できます。


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'[^\\/]+(?![\\/])$'。「正規表現のチャレンジ」の場合、これはスラッシュの正の前方先読みを負の前方先読みに変更し、スラッシュで終わるパス名がパス名の最後のサブディレクトリの代わりに何も返さないようにします。もちろん、潜在的なファイル名が実際にファイルを参照していること、そのために使用する必要がある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
ファイル名またはディレクトリにスペースが含まれている場合はどうなりますか?
クリス

1
直接split( "/")[-1]はどうですか?
ナン

4

ダブルバックスラッシュパスは見たことがありませんが、存在しますか?osそれらのpythonモジュールの組み込み機能は失敗します。他のすべては機能します、またあなたによって与えられた警告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

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.