Extraiga el nombre del archivo de la ruta, sin importar el formato del sistema operativo / ruta

¿Qué biblioteca de Python puedo usar para extraer nombres de archivo de las rutas, sin importar cuál sea el sistema operativo o el formato de la ruta?

Por ejemplo, me gustaría que todos estos caminos me devolvieran 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

preguntado el 05 de diciembre de 11 a las 07:12

Actualice porque las respuestas son métodos más antiguos. biblioteca estándar: pathlib.Path fue diseñado para esto -

21 Respuestas

De hecho, hay un función que devuelve exactamente lo que quieres

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

ADVERTENCIA: Cuando os.path.basename() se utiliza en un sistema POSIX para obtener el nombre base de una ruta con estilo de Windows (p. ej. "C:\\my\\file.txt"), se devolverá la ruta completa.

Ejemplo a continuación del shell interactivo de Python que se ejecuta en un host Linux:

Python 3.8.2 (default, Mar 13 2020, 10:14:16)
[GCC 9.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> filepath = "C:\\my\\path\\to\\file.txt" # A Windows style file path.
>>> os.path.basename(filepath)
'C:\\my\\path\\to\\file.txt'

Respondido el 24 de junio de 20 a las 15:06

Si desea procesar rutas de manera independiente del sistema operativo, entonces para os.path.basename (u "C: \\ temp \\ bla.txt") espera obtener 'bla.txt'. La cuestión no se trata de obtener un nombre de archivo válido, sino de extraer el nombre de una ruta. - Adi Roiban

En mi búsqueda de Google para encontrar el nombre de archivo de una ruta, esta respuesta fue la más útil. De todos modos, mi caso de uso es solo en Windows. - bobort

os.path.basename(your_path) ¡Esto funcionó! Quería ruta de script: os.path.dirname(os.path.realpath(__file__)) y nombre de la secuencia de comandos: os.path.basename(os.path.realpath(__file__)). ¡Gracias! - Los datos que caminan

@AdiRoiban ¿Podría elaborar su comentario? Lo probé en Windows 7 y de hecho obtengo "bla.txt". Simplemente digo, no veo ningún problema (para mí). - john cj

@ johnc.j. El punto es que, cuando intentaste hacer esto en Linux, obtendrías 'C:\\temp\\bla.txt' en lugar de. - moooeeeeep

Usar os.path.split or os.path.basename como 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 una barra invertida o una 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 todos(1) caminos en todas las plataformas.

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

Por supuesto, si el archivo termina con una barra, el nombre base estará vacío, así que cree su propia función para manejarlo:

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: nombres de archivos de Linux puede 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 a la c presentar en el b subcarpeta del a carpeta. Por tanto, cuando se utilizan barras inclinadas hacia delante y hacia atrás en una ruta, necesitas 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 no crear agujeros de seguridad accidentales.

Respondido 28 Abr '13, 22:04

en Windows, os.path solo carga el ntpath módulo internamente. Con este módulo, es posible manejar el '\\' separadores de ruta incluso en máquinas Linux. Para Linux el posixpath módulo (resp. os.path) simplificará las operaciones de ruta para permitir solo el estilo posix '/' separadores. - moooeeeeep

@moooeeeep Entonces, podríamos usar la respuesta de Stranac, ¿y es confiable? ("Usar os.path.split u os.path.basename como otros sugieren 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á" - la cita es de la publicación de Lauritz - y no entiendo, esta advertencia se refiere a la respuesta de Stranac o no). - john cj

@ johnc.j. Solo cuando necesite analizar las rutas de estilo de Windows (por ejemplo, r'C:\path\to\file.txt') en una máquina Linux, debe utilizar el módulo ntpath. De lo contrario, puede utilizar las funciones de os.path. Esto se debe a que los sistemas Linux normalmente permiten el uso de la barra invertida en los nombres de archivo (como se explica en la respuesta). - moooeeeeep

¿No es tu solución equivalente a os.path.basename(os.path.normpath(path)) ? - Sr_y_Sra_D

Por lo que vale para los futuros visitantes de esta pregunta, me encontré con la situación sobre la que estaba advirtiendo Lauritz y su solución fue la única que funcionó. Ningún financiamiento con sistema operativo podría generar solo el nombre del archivo. Así que en mi humilde opinión, ntpath es el camino a seguir. - Harabeck

os.path.split es la función que estás buscando

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

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

Respondido el 17 de enero de 18 a las 15:01

Solo para que otros usuarios tengan cuidado, esto devuelve "" si las rutas terminan en "/" o "\" - Zumbido

Cuando intento "C: \ Users \ Dell \ Desktop \ ProjectShadow \ button \ button.py" devuelve este "ProjectShadowuttontton "para todo lo que no sea esto, devuelve el resultado correcto - amitnair92

@ amitnair92: haga esto: r "C: \ Users \ Dell \ Desktop \ ProjectShadow \ button \ button.py" o esto: "C: \\ Users \\ Dell \\ Desktop \\ ProjectShadow \\ button \\ button .py "-" \ b "es un carácter especial (creo que el sistema 'campana'), similar a cómo \ r o \ n significan nueva línea / retorno de carro. Prefijar la cadena con r "C: \ ..." significa usar la entrada sin procesar dada - bruce lamond

En Python 3

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

Respondido 03 Feb 18, 04:02

3.4 a 3.6 o posterior, dependiendo exactamente de los elementos de pathlib que utilice. - luzcc

también puede usar Path ("some / path / to / file.dat"). stem para obtener el nombre del archivo sin la extensión del archivo - s2t2

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

tail es lo que quieres, el nombre del archivo.

Ver Documentos del módulo del sistema operativo python para el detalle

Respondido 24 Feb 20, 01:02

Solo para que otros usuarios tengan cuidado, esto devuelve "" si las rutas terminan en "/" o "\" - Zumbido

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

Respondido el 06 de Septiembre de 19 a las 04:09

Si desea obtener el nombre del archivo automáticamente, puede hacerlo

import glob

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

Respondido 25 Oct 19, 11:10

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

esto volverá: paint.exe

cambie el valor sep de la función de división con respecto a su ruta o sistema operativo.

respondido 03 nov., 14:07

Esta es la respuesta que me gustó, pero ¿por qué no hacer lo siguiente? fname = str(path).split('/')[-1] - asultan904

En su ejemplo, también deberá quitar la barra de la derecha del lado derecho para volver 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 lazyr ha proporcionado la respuesta correcta. Mi código no funcionará con rutas similares a Windows en sistemas Unix y viceversa en comparación con rutas similares a Unix en sistemas Windows.

Respondido el 05 de diciembre de 11 a las 12:12

Tu respuesta no funcionará para r"a\b\c" en linux, ni para "a/b/c" en las ventanas. - Lauritz V. Thaulow

por supuesto, os.path.basename(path) solo funcionará si os.path.isfile(path) is True. Por lo tanto path = 'a/b/c/' no es un nombre de archivo válido en absoluto ... - moooeeeeep

@fmaas os.path.basename es puramente una función de procesamiento de cadenas. No le importa si el archivo existe o si es un archivo o un directorio. os.path.basename("a/b/c/") devoluciones "" debido a la barra inclinada final. - Lauritz V. Thaulow

lazyr ¡tienes razón! No pensé en eso. ¿Sería seguro hacerlo? path = path.replace('\\', '/') ? - Esquíes

@Skirmantas, supongo, pero no se siente bien. Creo que el procesamiento de rutas debe realizarse con las herramientas integradas que se crearon para el trabajo. Hay mucho más a caminos de lo que parece. - Lauritz V. Thaulow

Mi favorito personal es:

filename = fullname.split(os.sep)[-1]

Respondido el 17 de diciembre de 20 a las 17:12

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

Respondido el 18 de junio de 15 a las 16:06

Si la ruta de su archivo no termina con "/" y los directorios separados por "/", utilice el siguiente código. Como sabemos, generalmente, 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 que terminan con "/", use 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 está marcada por "\", que generalmente 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 función al verificar el tipo de sistema operativo y devolver el resultado.

Respondido 19 Feb 19, 05:02

Aquí hay una solución solo para 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 solo quieres un posible nombre de archivo, si está presente (es decir, /a/b/ es un directorio y también lo es c:\windows\), cambie la expresión regular a: r'[^\\/]+(?![\\/])$' . Para el "regex desafiado", esto cambia la anticipación positiva para una especie de barra a un avance negativo, lo que provoca que los nombres de ruta terminen con dicho tala para no devolver nada en lugar del último subdirectorio en el nombre de la ruta. Por supuesto, no hay garantía de que el posible nombre de archivo en realidad se refiere a un archivo y para eso os.path.is_dir() or os.path.is_file() necesitaría ser empleado.

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í.

contestado el 27 de mayo de 19 a las 16:05

estás usando re, ¿por qué no el módulo os? - Saurabh Chandra Patel

@SaurabhChandraPatel ha pasado mucho tiempo. Si mal no recuerdo, regex se usa como una solución multiplataforma en este caso. Puede procesar nombres de archivos de Windows en un servidor Linux, por ejemplo. - eric duminil

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] 

Obteniendo los valores de abc.name será una cadena como esta: '/tmp/tmpks5oksk7' Entonces 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.

Respondido el 26 de Septiembre de 19 a las 11:09

¿Qué pasa si el nombre del archivo o un directorio contiene un espacio? - Kris

¿Qué pasa con una división directa ("/") [- 1]? - Yaya

Si tiene varios archivos en un directorio y desea almacenar esos nombres de archivo en una lista. Utilice el siguiente código.

import os as os
import glob as glob
path = 'mypath'
file_list= []
for file in glob.glob(path):
    data_file_list = os.path.basename(file)
    file_list.append(data_file_list)

Respondido 13 Feb 21, 08:02

Nunca he visto caminos con doble barra diagonal inversa, ¿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))

respondido 19 mar '15, 21:03

Esos no son golpes dobles. Son barras diagonales inversas únicas y es necesario escapar de ellas. - eric duminil

El separador de Windows puede estar en un nombre de archivo Unix o en una 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 dividirá y devolverá el valor más a la derecha. Es feo, pero simple según 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])

contestado el 16 de mayo de 16 a las 16:05

Además, no dude en enviarme sugerencias sobre cómo formatear en este lugar. Tomó media docena de intentos para poner el código de muestra en su lugar. - dusc2don

En aras de la integridad, aquí está el 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.

Respondido 24 ago 17, 15:08

Tanto en Python 2 como en 3, usando el módulo caminolib2:

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 su 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 todos los caminos en la representación interna unificada de pathlib2, con diferentes decodificadores según la plataforma. Afortunadamente, pathlib2 incluye un decodificador genérico llamado PurePath que debería funcionar en cualquier camino. En caso de que esto no funcione, puede forzar el reconocimiento de la ruta de Windows usando 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 nojoin=False, la ruta se volverá a unir, de modo que la salida sea simplemente la cadena de entrada convertida a un formato Unix, que puede ser útil para comparar subrutas entre plataformas.

Respondido el 28 de diciembre de 18 a las 22:12

Utilizo este método en Windows y Ubuntu (WSL) y funciona como (I) esperaba solo usando 'import os': Entonces, básicamente, replace () coloque el separador de ruta correcto en función de su plataforma de sistema operativo actual.

Si la ruta termina con una barra inclinada '/', entonces no es un archivo sino un directorio, por lo que devuelve una cadena vacía.

import os

my_fullpath = r"D:\MY_FOLDER\TEST\20201108\20201108_073751.DNG"
os.path.basename(my_fullpath.replace('\\',os.sep))

my_fullpath = r"/MY_FOLDER/TEST/20201108/20201108_073751.DNG"
os.path.basename(my_fullpath.replace('\\',os.sep))

my_fullpath = r"/MY_FOLDER/TEST/20201108/"
os.path.basename(my_fullpath.replace('\\',os.sep))

my_fullpath = r"/MY_FOLDER/TEST/20201108"
os.path.basename(my_fullpath.replace('\\',os.sep))

En Windows (izquierda) y Ubuntu (a través de WSL, derecha): enter image description here

Respondido el 08 de Septiembre de 21 a las 04:09

¡Es trabajo!

os.path.basename(name)

Pero no puede obtener el nombre del archivo en Linux con la ruta del archivo de Windows. Windows también. os.path carga un módulo diferente en un sistema de operador diferente:

  • Linux - ruta posix
  • Windows-npath

Entonces puedes usar os.path para obtener el resultado correcto siempre

Respondido 18 ago 21, 02:08

Asegúrese de que su solución no se haya propuesto ya en otras respuestas como la uno superior. También hay algunas advertencias que se describen en estas preguntas principales y sus comentarios. - sergey shubin

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.