Respuestas:
Usar os.path.split
o, os.path.basename
como lo sugieren otros, no funcionará en todos los casos: si está ejecutando el script en Linux e intenta procesar una ruta clásica al estilo de Windows, fallará.
Las rutas de Windows pueden usar barra diagonal inversa o barra diagonal como separador de ruta. Por lo tanto, el ntpath
módulo (que es equivalente a os.path cuando se ejecuta en Windows) funcionará para todas las (1) rutas en todas las plataformas.
import ntpath
ntpath.basename("a/b/c")
Por supuesto, si el archivo termina con una barra oblicua, el nombre base estará vacío, así que haga su propia función para tratarlo:
def path_leaf(path):
head, tail = ntpath.split(path)
return tail or ntpath.basename(head)
Verificación:
>>> 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) Hay una advertencia: los nombres de archivo de Linux pueden contener barras invertidas . Entonces, en Linux, r'a/b\c'
siempre se refiere al archivo b\c
en la a
carpeta, mientras que en Windows, siempre se refiere al c
archivo en la b
subcarpeta de la a
carpeta. Entonces, cuando se utilizan barras diagonales hacia adelante y hacia atrás en una ruta, debe conocer la plataforma asociada para poder interpretarla correctamente. En la práctica, generalmente es seguro asumir que es una ruta de Windows, ya que las barras invertidas rara vez se usan en los nombres de archivos de Linux, pero tenga esto en cuenta cuando codifique para que no cree agujeros de seguridad accidentales.
r'C:\path\to\file.txt'
) en una máquina Linux, necesita usar el módulo ntpath. De lo contrario, puede usar las funciones de os.path. Esto se debe a que los sistemas Linux normalmente permiten el uso de los caracteres de barra diagonal inversa en los nombres de archivo (como se explica en la respuesta).
os.path.basename(os.path.normpath(path))
?
En realidad, hay una función que devuelve exactamente lo que quieres
import os
print(os.path.basename(your_path))
os.path.basename(your_path)
Esto funcionó! Quería ruta del script: os.path.dirname(os.path.realpath(__file__))
y el nombre del script: os.path.basename(os.path.realpath(__file__))
. ¡Gracias!
'C:\\temp\\bla.txt'
lugar.
os.path.split es la función que busca
head, tail = os.path.split("/tmp/d/a.dat")
>>> print(tail)
a.dat
>>> print(head)
/tmp/d
import os
head, tail = os.path.split('path/to/file.exe')
cola es lo que quieres, el nombre del archivo.
Consulte los documentos del módulo del sistema operativo Python para obtener más detalles.
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
En su ejemplo, también necesitará quitar una barra diagonal del lado derecho para regresar 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 nivel:
>>> os.path.filename(os.path.dirname(path))
'b'
Actualización: creo que lazyr
ha proporcionado la respuesta correcta. Mi código no funcionará con rutas similares a Windows en sistemas Unix y viceversa frente a rutas similares a Unix en sistemas Windows.
r"a\b\c"
en Linux, ni "a/b/c"
en Windows.
os.path.basename(path)
solo funcionará si os.path.isfile(path)
es así True
. Por path = 'a/b/c/'
lo tanto, no es un nombre de archivo válido en absoluto ...
os.path.basename("a/b/c/")
vuelve ""
debido a la barra inclinada final.
lazyr
¡tienes razón! No pensé en eso. ¿Sería seguro hacerlo solo path = path.replace('\\', '/')
?
fname = str("C:\Windows\paint.exe").split('\\')[-1:][0]
esto devolverá: paint.exe
cambie el valor de la función de división con respecto a su ruta o sistema operativo.
fname = str(path).split('/')[-1]
Si la ruta del archivo no terminó con "/" y los directorios están separados por "/", utilice el siguiente código. Como sabemos en general, la ruta no termina con "/".
import os
path_str = "/var/www/index.html"
print(os.path.basename(path_str))
Pero en algunos casos, como las URL terminan con "/", utilice el siguiente código
import os
path_str = "/home/some_str/last_str/"
split_path = path_str.rsplit("/",1)
print(os.path.basename(split_path[0]))
pero cuando su ruta se deletrea con "\", que generalmente se encuentra en las rutas de Windows, puede usar los siguientes 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]))
Puede combinar ambos en una sola función marcando el tipo de sistema operativo y devolviendo el resultado.
Esto también funciona para Linux y Windows con la biblioteca estándar
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']
Aquí hay una solución de expresiones regulares, que parece funcionar con cualquier ruta de sistema operativo en cualquier sistema operativo.
No se necesita ningún otro módulo, y tampoco se necesita preprocesamiento:
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']
Actualizar:
Si sólo desea un potencial de nombre de archivo, si está presente (es decir, /a/b/
es un directorio y también lo es c:\windows\
), cambiar la expresión regular a: r'[^\\/]+(?![\\/])$'
. Para el "regex desafiado", esto cambia la búsqueda anticipada positiva para algún tipo de barra diagonal a una vista anticipada negativa, lo que hace que los nombres de ruta que terminan con dicha barra no devuelvan nada en lugar del último subdirectorio en la ruta. Por supuesto, no hay garantía de que el nombre de archivo potencial realmente se refiera a un archivo y para eso os.path.is_dir()
o os.path.is_file()
deba emplearse.
Esto coincidirá de la siguiente manera:
/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
La expresión regular se puede probar aquí .
Tal vez solo mi solución todo en uno sin importantes novedades (considere el archivo temporal para crear archivos temporales: D)
import tempfile
abc = tempfile.NamedTemporaryFile(dir='/tmp/')
abc.name
abc.name.replace("/", " ").split()[-1]
Obtener los valores de abc.name
será una cadena como esta: '/tmp/tmpks5oksk7'
así puedo reemplazar el /
con un espacio .replace("/", " ")
y luego llamar split()
. Eso devolverá una lista y obtengo el último elemento de la lista con[-1]
No es necesario importar ningún módulo.
Nunca he visto caminos con doble barra invertida, ¿existen? La característica incorporada del módulo python os
falla para aquellos. Todos los demás funcionan, también la advertencia dada por usted con 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))
El separador de Windows puede estar en un nombre de archivo Unix o ruta de Windows. El separador de Unix solo puede existir en la ruta de Unix. La presencia de un separador de Unix indica una ruta que no es de Windows.
Lo siguiente eliminará (cortará el separador final) por el separador específico del sistema operativo, luego se dividirá y devolverá el valor más a la derecha. Es feo, pero simple basado en la suposición anterior. Si la suposición es incorrecta, actualice y actualizaré esta respuesta para que coincida con las condiciones más precisas.
a.rstrip("\\\\" if a.count("/") == 0 else '/').split("\\\\" if a.count("/") == 0 else '/')[-1]
Código de muestra:
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, aquí está la pathlib
solución para 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']
Esto funciona tanto en Windows como en Linux.
En Python 2 y 3, usando el 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']
Con tu caso de prueba:
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
La idea aquí es convertir todas las rutas en la representación interna unificada de pathlib2
, con diferentes decodificadores dependiendo de la plataforma. Afortunadamente, pathlib2
incluye un decodificador genérico llamado PurePath
que debería funcionar en cualquier ruta. En caso de que esto no funcione, puede forzar el reconocimiento de la ruta de Windows utilizando fromwinpath=True
. Esto dividirá la cadena de entrada en partes, la última es la hoja que está buscando, de ahí la path2unix(t)[-1]
.
Si el argumento es nojoin=False
, la ruta se volverá a unir, por lo que la salida es simplemente la cadena de entrada convertida a un formato Unix, que puede ser útil para comparar subrutas en las plataformas.
os.path
solo carga elntpath
módulo internamente. Con este módulo, es posible manejar los'\\'
separadores de ruta incluso en máquinas Linux. Para Linux, elposixpath
módulo (resp.os.path
) Simplificará las operaciones de ruta para permitir solo'/'
separadores de estilo posix .