Was ist der richtige Weg, um mehrere Pfadkomponenten in einen einzigen vollständigen Pfad in Emacs Lisp zu verbinden?
-
09-10-2019 - |
Frage
Angenommen, ich Variablen dir
und file
enthalten Strings haben ein Verzeichnis und einen Dateinamen repräsentieren. Was ist der richtige Weg in Emacs Lisp sie in einen vollständigen Pfad zur Datei verbinden?
Zum Beispiel, wenn dir
ist "/usr/bin"
und file
ist "ls"
, dann will ich "/usr/bin/ls"
. Aber wenn statt dir
"/usr/bin/"
ist, möchte ich noch das gleiche, ohne wiederholt Strich.
Lösung
das Handbuch zu lesen, durch für Verzeichnis Namen , werden Sie die Antwort finden:
ein Verzeichnisname gegeben, können Sie kombinieren es mit einer relativen Dateinamen
concat
:(concat dirname relfile)
Seien Sie sicher, zu überprüfen, ob der Dateiname relativ bevor Sie das tun. Wenn du benutzt ein absoluter Dateiname, die Ergebnisse könnte syntaktisch ungültig oder beziehen sich auf die falsche Datei.
Wenn Sie ein Verzeichnis-Datei verwenden möchten nennen eine solche Kombination bei der Herstellung, Sie muss es zuerst in ein Verzeichnis konvertieren Namen mit
file-name-as-directory
:(concat (file-name-as-directory dirfile) relfile)
Versuchen Sie nicht, verketten einen Schrägstrich von Hand, wie in
;;; Wrong! (concat dirfile "/" relfile)
, weil dies nicht tragbar ist. Immer Verwendung
file-name-as-directory
.
Andere Befehle, die nützlich sind, sind: file-name-directory
, file-name-nondirectory
, und andere in der Dateiname Komponenten Abschnitt.
Andere Tipps
Sie können expand-file-name
für diese verwenden:
(expand-file-name "ls" "/usr/bin")
"/usr/bin/ls"
(expand-file-name "ls" "/usr/bin/")
"/usr/bin/ls"
Edit: das funktioniert nur mit absoluten Verzeichnisnamen. Ich denke, Trey Antwort ist die bevorzugte Lösung.
wollte ich mehrere verschachtelte Verzeichnisse auf einen Pfad verbinden. Ursprünglich verwendete ich mehrere expand-file-name
Anrufe, etwa so:
(expand-file-name "b" (expand-file-name "a" "/tmp"))
"/tmp/a/b"
Dies ist jedoch ziemlich ausführlich, und liest nach hinten.
Stattdessen schrieb ich eine Funktion, die wie Pythons os.path.join
wirkt:
(defun joindirs (root &rest dirs)
"Joins a series of directories together, like Python's os.path.join,
(dotemacs-joindirs \"/tmp\" \"a\" \"b\" \"c\") => /tmp/a/b/c"
(if (not dirs)
root
(apply 'joindirs
(expand-file-name (car dirs) root)
(cdr dirs))))
Es funktioniert wie folgt:
(joindirs "/tmp" "a" "b")
"/tmp/a/b"
(joindirs "~" ".emacs.d" "src")
"/Users/dbr/.emacs.d/src"
(joindirs "~" ".emacs.d" "~tmp")
"/Users/dbr/.emacs.d/~tmp"
Hier ist, was ich benutze:
(defun catdir (root &rest dirs)
(apply 'concat (mapcar
(lambda (name) (file-name-as-directory name))
(push root dirs))))
Die Unterschiede von @ DBR:
- Gibt einen „Emacs Verzeichnisnamen“, das heißt einen Wert mit einem Schrägstrich
- Es ist erweitert nicht den Weg, wenn
root
relativ (siehe Anmerkungen) - Treats
root
als die Wurzel, währendjoindirs
wird verwenden Sie die zuerst Komponente beginnend mit"/"
als Wurzel.
Notizen
Viele Dateihandhabungsfunktionen (alle, die meisten, ???) werden redundante Schrägstriche normalisieren und Call expand-file-name
(oder ähnliches) auf relative Pfade, so # 2 und # 3 kann nicht wirklich wichtig.
Wenn Sie eine bequeme Datei- und Verzeichnis Manipulation Bibliothek f.el
, müssen Sie nur f-join
. Der Code unten ist für diejenigen, die aus irgendeinem Grunde Müll diese Bibliothek zu verwenden.
(defun os-path-join (a &rest ps)
(let ((path a))
(while ps
(let ((p (pop ps)))
(cond ((string-prefix-p "/" p)
(setq path p))
((or (not path) (string-suffix-p "/" p))
(setq path (concat path p)))
(t (setq path (concat path "/" p))))))
path))
Diese verhält sich genau so, wie Pythons os.path.join
.
ELISP> (os-path-join "~" "a" "b" "")
"~/a/b/"
ELISP> (os-path-join "~" "a" "/b" "c")
"/b/c"
string-suffix-p
existiert nicht vor Emacs 24.4 , so dass ich mit ein, wenn ein String endet meine eigenen prüfen schrieb Suffix in Emacs Lisp .
Diese Frage wurde im Jahr 2010 gefragt, aber zum Zeitpunkt des Schreibens ist es der Top-Hit für Suchanfrage wie „join Dateipfade in elisp“ , so dachte ich, dass ich die Antwort aktualisieren würde.
Seit 2010 haben sich die Dinge auf eine Menge in der Welt der Emacs bewegt. Das ist so etwas wie eine doppelte Antwort, da sie kurz in einer Antwort unter erwähnt wurden, aber ich werde es ein wenig konkretisieren . Es gibt jetzt eine spezielle Bibliothek für Datei-Interaktionen, f.el
:
inspiriert viel von @magnars ist ausgezeichnet s.el und dash.el , f.el ist ein modernes API für die Arbeit mit Dateien und Verzeichnissen in Emacs .
Versuchen Sie nicht, das Rad neu zu erfinden. Sie sollten diese Bibliothek für Dateipfad Manipulationen verwenden. Die gewünschte Funktion ist f-join
:
(f-join "path") ;; => "path"
(f-join "path" "to") ;; => "path/to"
(f-join "/" "path" "to" "heaven") ;; => "/path/to/heaven"
Möglicherweise müssen Sie das Paket zuerst installieren. Es sollte auf Melpa zur Verfügung.