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 archivos de rutas, sin importar cuál sea el sistema operativo o el formato de ruta?

Por ejemplo, me gustaría que todos estos caminos me devuelvan 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
 458
Author: martineau, 2011-12-05

14 answers

Usar os.path.split o 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á.

Las rutas de Windows pueden usar una barra invertida o una barra diagonal como separador de rutas. Por lo tanto, el módulo ntpath (que es equivalente a os.ruta de acceso 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 haga su propia función para tratar con él:

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. Así que en linux, r'a/b\c' siempre se refiere al archivo b\c en la carpeta a, mientras que en Windows, siempre se refiere al archivo c en la subcarpeta b de la carpeta a. Por lo tanto, cuando se usan barras hacia adelante y hacia atrás en una ruta, necesita conocer la plataforma asociada para poder interprete 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 archivo de Linux, pero tenga esto en cuenta cuando codifique para no crear agujeros de seguridad accidentales.

 507
Author: Lauritz V. Thaulow,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-28 21:12:59

En realidad, hay una función que devuelve exactamente lo que quieres

print(os.path.basename(your_path))
 742
Author: stranac,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-17 15:43:17

Os.camino.split es la función que está buscando

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

>>> print(tail)
a.dat
>>> print(head)
/tmp/d
 142
Author: Jakob Bowyer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-17 15:43:38
import os
head, tail = os.path.split(p)
print tail

Supongamos que p es la cadena de entrada, tail es lo que quieres.

Ver python os module docs para más detalles

 30
Author: number5,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-12-05 11:45:21

En python 3

>>> from pathlib import Path    
>>> Path("/tmp/d/a.dat").name
'a.dat'
 10
Author: Kishan B,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-03 04:06:11

En su ejemplo también tendrá que quitar la barra diagonal 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 que lazyr ha proporcionado la respuesta correcta. Mi código no funcionará con rutas similares a Windows en sistemas unix y vice versus con rutas similares a unix en el sistema windows.

 9
Author: Ski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-12-05 12:27:43
fname = str("C:\Windows\paint.exe").split('\\')[-1:][0]

Esto devolverá : pintura.exe

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

 6
Author: Eslam Hamouda,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-11-03 07:39:49

Esto funciona para linux y Windows, así como 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']
 6
Author: Csabka,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-06-18 15:39:19

Nunca he visto caminos de doble barra invertida, ¿existen? La característica incorporada del módulo python os falla para ellos. Todos los demás trabajan, 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))
 4
Author: PythoNic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-03-19 21:18:33

El separador de Windows puede estar en un nombre de archivo Unix o en una ruta de Windows. El separador Unix solo puede existir en la ruta Unix. La presencia de un separador Unix indica una ruta que no es de Windows.

Lo siguiente separará (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 basado en la suposición anterior. Si la suposición es incorrecta, actualice y actualizaré esta respuesta para que coincida con la más precisa condición.

a.rstrip("\\\\" if a.count("/") == 0 else '/').split("\\\\" if a.count("/") == 0 else '/')[-1]

Código de ejemplo:

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])
 3
Author: dusc2don,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-05-16 15:00:13

Tal vez solo mi solución todo en uno sin algo importante nuevo (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í que puedo reemplazar el / con un espacio .replace("/", " ") y luego llamar split(). Eso devolverá una lista y obtendré el último elemento de la lista con [-1]

No es necesario importar ningún módulo.

Saludos cordiales

4k3nd0

 2
Author: Akendo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-08-21 15:23:01

Aquí hay una solución regex, que parece funcionar con cualquier ruta del 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']

La expresión regular se puede probar aquí.

 2
Author: Eric Duminil,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-01-17 15:44:10

Para completar, aquí está la solución pathlib 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.

 1
Author: Morgoth,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-24 14:31:00
filename = path[path.rfind('/')+1:]
 -5
Author: Qiyun,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-05 23:20:05