Was ist der richtige Weg, um mehrere Pfadkomponenten in einen einzigen vollständigen Pfad in Emacs Lisp zu verbinden?

StackOverflow https://stackoverflow.com/questions/3964715

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.

War es hilfreich?

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:

  1. Gibt einen „Emacs Verzeichnisnamen“, das heißt einen Wert mit einem Schrägstrich
  2. Es ist erweitert nicht den Weg, wenn root relativ (siehe Anmerkungen)
  3. Treats root als die Wurzel, während joindirs 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.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top