Respostas:
Usar os.path.splitou os.path.basenamecomo outros sugerem não funcionará em todos os casos: se você estiver executando o script no Linux e tentar processar um caminho clássico no estilo Windows, ele falhará.
Os caminhos do Windows podem usar barra invertida ou barra invertida como separador de caminho. Portanto, o ntpathmódulo (que é equivalente ao os.path ao executar no Windows) funcionará para todos os (1) caminhos em todas as plataformas.
import ntpath
ntpath.basename("a/b/c")
Obviamente, se o arquivo terminar com uma barra, o nome da base ficará vazio; portanto, faça sua própria função para lidar com isso:
def path_leaf(path):
head, tail = ntpath.split(path)
return tail or ntpath.basename(head)
Verificação:
>>> 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) Há uma ressalva: os nomes de arquivos do Linux podem conter barras invertidas . Portanto, no linux, r'a/b\c'sempre se refere ao arquivo b\cna apasta, enquanto no Windows, sempre se refere ao carquivo na bsubpasta da apasta. Portanto, quando ambas as barras são usadas em um caminho, você precisa conhecer a plataforma associada para poder interpretá-la corretamente. Na prática, geralmente é seguro assumir que é um caminho do Windows, já que as barras invertidas raramente são usadas nos nomes de arquivos do Linux, mas lembre-se disso quando você codificar para não criar falhas acidentais na segurança.
r'C:\path\to\file.txt') em uma máquina Linux, precisará usar o módulo ntpath. Caso contrário, você pode usar as funções do os.path. Isso ocorre porque os sistemas Linux normalmente permitem o uso dos caracteres de barra invertida nos nomes de arquivos (conforme explicado na resposta).
os.path.basename(os.path.normpath(path))?
Na verdade, há uma função que retorna exatamente o que você deseja
import os
print(os.path.basename(your_path))
os.path.basename(your_path)Isso funcionou! Eu queria caminho do script: os.path.dirname(os.path.realpath(__file__))eo nome do script: os.path.basename(os.path.realpath(__file__)). Obrigado!
'C:\\temp\\bla.txt'.
os.path.split é a função que você está procurando
head, tail = os.path.split("/tmp/d/a.dat")
>>> print(tail)
a.dat
>>> print(head)
/tmp/d
Em python 3
>>> from pathlib import Path
>>> Path("/tmp/d/a.dat").name
'a.dat'
import os
head, tail = os.path.split('path/to/file.exe')
cauda é o que você quer, o nome do arquivo.
Veja os documentos do módulo OS do python para obter detalhes
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
No seu exemplo, você também precisará remover a barra do lado direito para retornar c:
>>> import os
>>> path = 'a/b/c/'
>>> path = path.rstrip(os.sep) # strip the slash from the right side
>>> os.path.basename(path)
'c'
Segundo nível:
>>> os.path.filename(os.path.dirname(path))
'b'
atualização: acho lazyrque forneceu a resposta certa. Meu código não funcionará com caminhos semelhantes a janelas em sistemas unix e vice-versa com caminhos semelhantes a unix em sistemas Windows.
r"a\b\c"no linux, nem "a/b/c"no windows.
os.path.basename(path)só funcionará se os.path.isfile(path)for True. Portanto, path = 'a/b/c/'não é um nome de arquivo válido ...
os.path.basename("a/b/c/")retorna ""devido à barra final.
lazyrvocê está certo! Eu não pensei sobre isso. Seria seguro apenas fazer path = path.replace('\\', '/')?
fname = str("C:\Windows\paint.exe").split('\\')[-1:][0]
isso retornará: paint.exe
altere o valor sep da função de divisão em relação ao seu caminho ou SO.
fname = str(path).split('/')[-1]
Se o caminho do arquivo não terminar com "/" e os diretórios separados por "/", use o código a seguir. Como sabemos, geralmente o caminho não termina com "/".
import os
path_str = "/var/www/index.html"
print(os.path.basename(path_str))
Mas, em alguns casos, como os URLs terminam com "/", use o seguinte código
import os
path_str = "/home/some_str/last_str/"
split_path = path_str.rsplit("/",1)
print(os.path.basename(split_path[0]))
mas quando seu caminho é marcado por "\", que você geralmente encontra nos caminhos do Windows, pode usar os seguintes códigos
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]))
Você pode combinar as duas em uma função, verificando o tipo de SO e retornando o resultado.
Isso funciona para linux e windows, bem como para a biblioteca padrão
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]
Resultados:
['c', 'c', 'c', 'c', 'c', 'c', 'c']
Aqui está uma solução somente regex, que parece funcionar com qualquer caminho do sistema operacional em qualquer sistema operacional.
Nenhum outro módulo é necessário e também não é necessário pré-processamento:
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']
Atualizar:
Se você quiser apenas uma potencial filename, se presente (ou seja, /a/b/é um dir e assim é c:\windows\), altere o regex para: r'[^\\/]+(?![\\/])$'. Para o "regex contestado", isso altera a aparência positiva positiva de algum tipo de barra para uma negativa negativa, fazendo com que os nomes de caminho que terminam com a barra não retornem nada, em vez do último subdiretório do nome do caminho. Obviamente, não há garantia de que o nome do arquivo em potencial se refira a um arquivo e, para isso, os.path.is_dir()ou os.path.is_file()precise ser empregado.
Isso corresponderá da seguinte forma:
/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
O regex pode ser testado aqui .
Talvez apenas a minha solução completa sem importantes novidades (considere o tempfile para criar arquivos temporários: D)
import tempfile
abc = tempfile.NamedTemporaryFile(dir='/tmp/')
abc.name
abc.name.replace("/", " ").split()[-1]
Obter os valores de abc.nameserá uma sequência como esta: '/tmp/tmpks5oksk7'
Para que eu possa substituir o /por um espaço .replace("/", " ")e depois chamar split(). Isso retornará uma lista e eu recebo o último elemento da lista com[-1]
Não é necessário importar nenhum módulo.
Nunca vi caminhos com barra invertida dupla, eles existem? O recurso interno do módulo python osfalha para eles. Todos os outros funcionam, também a ressalva dada por você com 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))
O separador do Windows pode estar em um nome de arquivo Unix ou em Caminho do Windows. O separador Unix pode existir apenas no caminho Unix. A presença de um separador Unix indica um caminho que não é do Windows.
A seguir, o separador específico do sistema operacional será separado (separador de corte cortado), depois será dividido e retornará o valor mais à direita. É feio, mas simples, com base no pressuposto acima. Se a suposição estiver incorreta, atualize e eu atualizarei esta resposta para atender às condições mais precisas.
a.rstrip("\\\\" if a.count("/") == 0 else '/').split("\\\\" if a.count("/") == 0 else '/')[-1]
Código de amostra:
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])
Para completar, aqui está a pathlibsolução para o python 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']
Isso funciona no Windows e Linux.
No Python 2 e 3, usando o módulo 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)
Uso:
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']
Com sua caixa de teste:
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
A idéia aqui é converter todos os caminhos na representação interna unificada de pathlib2, com diferentes decodificadores, dependendo da plataforma. Felizmente, pathlib2inclui um decodificador genérico chamado PurePathque deve funcionar em qualquer caminho. Caso isso não funcione, você pode forçar o reconhecimento do caminho do Windows usando fromwinpath=True. Isso dividirá a sequência de entrada em partes, a última é a folha que você está procurando, daí a path2unix(t)[-1].
Se o argumento nojoin=False, o caminho será juntado novamente, de forma que a saída seja simplesmente a sequência de entrada convertida para um formato Unix, que pode ser útil para comparar subcaminhos entre plataformas.
os.pathbasta carregar ontpathmódulo internamente. Usando este módulo, é possível manipular os'\\'separadores de caminho mesmo em máquinas Linux. Para Linux, oposixpathmódulo (resp.os.path) Simplificará as operações do caminho para permitir apenas'/'separadores de estilo posix .