Risposte:
L'uso os.path.split
o os.path.basename
come altri suggeriscono non funzionerà in tutti i casi: se si esegue lo script su Linux e si tenta di elaborare un percorso classico in stile Windows, non funzionerà.
I percorsi di Windows possono utilizzare la barra rovesciata o la barra in avanti come separatore di percorso. Pertanto, il ntpath
modulo (che equivale a os.path quando è in esecuzione su Windows) funzionerà per tutti (1) i percorsi su tutte le piattaforme.
import ntpath
ntpath.basename("a/b/c")
Naturalmente, se il file termina con una barra, il nome di base sarà vuoto, quindi crea la tua funzione per gestirlo:
def path_leaf(path):
head, tail = ntpath.split(path)
return tail or ntpath.basename(head)
Verifica:
>>> 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) C'è un avvertimento: i nomi di file Linux possono contenere barre rovesciate . Quindi su Linux, r'a/b\c'
si riferisce sempre al file b\c
nella a
cartella, mentre su Windows, si riferisce sempre al c
file nella b
sottocartella della a
cartella. Pertanto, quando vengono utilizzate barre sia in avanti che all'indietro in un percorso, è necessario conoscere la piattaforma associata per poterla interpretare correttamente. In pratica, di solito è sicuro supporre che sia un percorso di Windows poiché le barre rovesciate sono usate raramente nei nomi di file Linux, ma tienilo a mente quando scrivi il codice in modo da non creare falle di sicurezza accidentali.
r'C:\path\to\file.txt'
) Su una macchina Linux, è necessario utilizzare il modulo ntpath. Altrimenti, è possibile utilizzare le funzioni da os.path. Questo perché i sistemi Linux normalmente consentono l'uso dei caratteri backslash nei nomi dei file (come spiegato nella risposta).
os.path.basename(os.path.normpath(path))
?
In realtà, c'è una funzione che restituisce esattamente quello che vuoi
import os
print(os.path.basename(your_path))
os.path.basename(your_path)
Questo ha funzionato! Volevo percorso dello script: os.path.dirname(os.path.realpath(__file__))
e il nome script: os.path.basename(os.path.realpath(__file__))
. Grazie!
'C:\\temp\\bla.txt'
invece.
os.path.split è la funzione che stai cercando
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')
tail è quello che vuoi, il nome del file.
Vedi i documenti del modulo OS Python per i dettagli
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
Nel tuo esempio dovrai anche rimuovere la barra da destra a destra per tornare c
:
>>> import os
>>> path = 'a/b/c/'
>>> path = path.rstrip(os.sep) # strip the slash from the right side
>>> os.path.basename(path)
'c'
Secondo livello:
>>> os.path.filename(os.path.dirname(path))
'b'
aggiornamento: penso che lazyr
abbia fornito la risposta giusta. Il mio codice non funzionerà con percorsi simil-windows su sistemi unix e viceversa con percorsi simil-unix su sistemi windows.
r"a\b\c"
Linux, né per "a/b/c"
Windows.
os.path.basename(path)
funzionerà solo se lo os.path.isfile(path)
è True
. Pertanto path = 'a/b/c/'
non è affatto un nome file valido ...
os.path.basename("a/b/c/")
ritorna a ""
causa della barra finale.
lazyr
hai ragione! Non ci ho pensato. Sarebbe sicuro farlo path = path.replace('\\', '/')
?
fname = str("C:\Windows\paint.exe").split('\\')[-1:][0]
questo restituirà: paint.exe
cambia il valore sep della funzione split relativa al tuo percorso o sistema operativo.
fname = str(path).split('/')[-1]
Se il percorso del file non termina con "/" e le directory separate da "/", utilizzare il codice seguente. Come sappiamo generalmente il percorso non termina con "/".
import os
path_str = "/var/www/index.html"
print(os.path.basename(path_str))
Ma in alcuni casi come gli URL terminano con "/" quindi utilizzare il codice seguente
import os
path_str = "/home/some_str/last_str/"
split_path = path_str.rsplit("/",1)
print(os.path.basename(split_path[0]))
ma quando il tuo percorso è sperato da "\" che trovi generalmente nei percorsi di Windows, puoi usare i seguenti codici
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]))
È possibile combinare entrambi in una funzione controllando il tipo di sistema operativo e restituendo il risultato.
Funziona anche con Linux e Windows con la libreria standard
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]
risultati:
['c', 'c', 'c', 'c', 'c', 'c', 'c']
Ecco una soluzione solo per regex, che sembra funzionare con qualsiasi percorso del sistema operativo su qualsiasi sistema operativo.
Non è necessario nessun altro modulo e non è necessaria nemmeno la preelaborazione:
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']
Aggiornare:
Se si desidera solo un potenziale nome di file, se presente (vale a dire, /a/b/
è una directory e così è c:\windows\
), modificare la regex per: r'[^\\/]+(?![\\/])$'
. Per il "regex sfidato", questo cambia lo sguardo in avanti positivo per una sorta di barra in uno sguardo in avanti negativo, facendo sì che i nomi di percorso che terminano con tale barra non restituiscano nulla invece dell'ultima sottodirectory nel percorso. Naturalmente non vi è alcuna garanzia che il nome del file potenziale si riferisca effettivamente a un file e per questo os.path.is_dir()
o os.path.is_file()
dovrebbe essere impiegato.
Questo corrisponderà come segue:
/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
Il regex può essere testato qui .
Forse solo la mia soluzione tutto in uno senza importanti novità (per quanto riguarda il tempfile per creare file temporanei: D)
import tempfile
abc = tempfile.NamedTemporaryFile(dir='/tmp/')
abc.name
abc.name.replace("/", " ").split()[-1]
Ottenere i valori di abc.name
sarà una stringa come questa: '/tmp/tmpks5oksk7'
così posso sostituire il /
con uno spazio .replace("/", " ")
e quindi chiamare split()
. Ciò restituirà un elenco e ottengo l'ultimo elemento dell'elenco con[-1]
Non è necessario importare alcun modulo.
Non ho mai visto percorsi a doppia barra rovesciata, esistono? La funzione integrata del modulo Python os
non riesce per quelli. Tutti gli altri funzionano, anche l'avvertimento dato da te 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))
Il separatore di Windows può trovarsi in un nome file Unix o Percorso Windows. Il separatore Unix può esistere solo nel percorso Unix. La presenza di un separatore Unix indica un percorso non Windows.
Quanto segue rimuoverà (taglia il separatore finale) dal separatore specifico del sistema operativo, quindi dividerà e restituirà il valore più a destra. È brutto, ma semplice basato sul presupposto sopra. Se il presupposto non è corretto, si prega di aggiornare e aggiornerò questa risposta per soddisfare le condizioni più precise.
a.rstrip("\\\\" if a.count("/") == 0 else '/').split("\\\\" if a.count("/") == 0 else '/')[-1]
codice di esempio:
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])
Per completezza, ecco la pathlib
soluzione per 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']
Funziona su Windows e Linux.
In Python 2 e 3, usando il modulo 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 la tua testcase:
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
L'idea qui è quella di convertire tutti i percorsi nella rappresentazione interna unificata di pathlib2
, con diversi decodificatori a seconda della piattaforma. Fortunatamente, pathlib2
include un decodificatore generico chiamato PurePath
che dovrebbe funzionare su qualsiasi percorso. Nel caso in cui ciò non funzioni, è possibile forzare il riconoscimento del percorso di Windows utilizzando fromwinpath=True
. Questo dividerà la stringa di input in parti, l'ultima è la foglia che stai cercando, quindi la path2unix(t)[-1]
.
Se l'argomento nojoin=False
, il percorso verrà unito di nuovo, in modo che l'output sia semplicemente la stringa di input convertita in un formato Unix, che può essere utile per confrontare i percorsi secondari tra piattaforme.
os.path
carica semplicemente ilntpath
modulo internamente. Utilizzando questo modulo, è possibile gestire i'\\'
separatori di percorso anche su macchine Linux. Per Linux ilposixpath
modulo (resp.os.path
) Semplificherà le operazioni del percorso per consentire solo i'/'
separatori di stile posix .