62 votes

Quelle est la manière correcte de joindre plusieurs composants de chemin en un seul chemin complet dans emacs lisp ?

Supposons que j'ai des variables dir y file contenant des chaînes de caractères représentant un répertoire et un nom de fichier, respectivement . Quelle est la façon correcte, dans emacs lisp, de les joindre en un chemin complet vers le fichier ?

Par exemple, si dir est "/usr/bin" y file est "ls" alors je veux "/usr/bin/ls" . Mais si à la place dir est "/usr/bin/" je veux toujours la même chose, sans barre oblique répétée.

1 votes

La formulation du titre ("joindre plusieurs composants de chemin") est vraiment un peu plus générale que le problème réel, mais si quelqu'un cherche une solution qui gère les valeurs de "multiple" > 2, voir stackoverflow.com/questions/9694661

0 votes

Eh bien, si vous pouvez joindre deux composants, alors vous pouvez utiliser la récursion pour joindre un nombre arbitraire. Je suppose que je considère les deux problèmes comme équivalents par induction.

77voto

Trey Jackson Points 49816

En lisant le manuel de Noms de répertoire vous trouverez la réponse :

Étant donné un nom de répertoire, vous pouvez le combiner avec un nom de fichier relatif en utilisant concat :

 (concat dirname relfile)

Assurez-vous de vérifier que le nom du fichier est relatif avant de le faire. Si vous utilisez un nom de fichier absolu, les résultats pourraient être syntaxiquement invalides ou faire référence au mauvais fichier.

Si vous souhaitez utiliser un nom de fichier de répertoire dans une telle combinaison, vous devez devez d'abord le convertir en nom de en utilisant file-name-as-directory :

 (concat (file-name-as-directory dirfile) relfile) 

N'essayez pas de concaténer un slash à la main, comme dans

 ;;; Wrong!
 (concat dirfile "/" relfile) 

parce que ce n'est pas portable. Toujours utiliser file-name-as-directory .

D'autres commandes utiles sont : file-name-directory , file-name-nondirectory et d'autres dans le Nom du fichier Composants section.

7 votes

Duh, pas étonnant que je vois ces concat partout, même notre manuel encourage cette utilisation. Mais il est généralement préférable d'utiliser expand-file-name sauf dans les cas où vous souhaitez que le résultat final soit un fichier relatif.

0 votes

Pourquoi est-ce que expand-file-name préféré à concat ? En dehors de la question du style, je ne vois pas l'avantage pratique ?

1 votes

Vous pouvez également appeler convert-standard-filename sur le résultat si vous êtes intéressé par la portabilité ?

31voto

Huw Points 4070

Vous pouvez utiliser expand-file-name pour ça :

(expand-file-name "ls" "/usr/bin")
"/usr/bin/ls"
(expand-file-name "ls" "/usr/bin/")
"/usr/bin/ls"

Edit : cela ne fonctionne qu'avec des noms de répertoire absolus. Je pense que la réponse de Trey est la solution préférable.

11voto

dbr Points 66401

Je voulais joindre plusieurs répertoires imbriqués sur un chemin. À l'origine, j'utilisais plusieurs expand-file-name appels, comme ça :

(expand-file-name "b" (expand-file-name "a" "/tmp"))
"/tmp/a/b"

Cependant, cela est plutôt verbeux et se lit à l'envers.

Au lieu de cela, j'ai écrit une fonction qui agit comme la fonction de Python os.path.join :

(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))))

Cela fonctionne comme suit :

(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"

0 votes

@dbr, j'utilise une fonction similaire - voir ma réponse ci-dessous. Vous voulez commenter ce que j'ai décrit comme étant les différences et leurs avantages et inconvénients ?

7voto

JackCC Points 253

Cette question a été posée en 2010, mais à l'heure où nous écrivons ces lignes, elle arrive en tête des recherches telles que "joindre les chemins de fichiers en elisp" alors j'ai pensé que je devais mettre à jour la réponse.

Depuis 2010, les choses ont beaucoup évolué dans le monde d'Emacs. Il s'agit en quelque sorte d'une réponse en double, puisqu'elle a été brièvement mentionnée dans une réponse en dessous de mais je vais l'étoffer un peu. Il y a maintenant un bibliothèque dédiée pour les interactions entre fichiers, f.el :

Très inspiré par @magnars de l'excellent s.el y dash.el , f.el est une API moderne pour travailler avec les fichiers et les répertoires dans Emacs.

N'essayez pas de réinventer la roue. Vous devriez utiliser cette bibliothèque pour les manipulations de chemins de fichiers. La fonction que vous voulez est f-join :

(f-join "path")                   ;; => "path"
(f-join "path" "to")              ;; => "path/to"
(f-join "/" "path" "to" "heaven") ;; => "/path/to/heaven"

Vous devrez peut-être d'abord installer le paquet. Il devrait être disponible sur MELPA.

4voto

sindikat Points 3533

Si vous utilisez une bibliothèque pratique de manipulation de fichiers et de répertoires f.el vous avez seulement besoin f-join . Le code ci-dessous est destiné à ceux qui, pour une raison quelconque, refusent d'utiliser cette bibliothèque.

(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))

Cela se comporte exactement comme l'outil Python os.path.join .

ELISP> (os-path-join "~" "a" "b" "")
"~/a/b/"
ELISP> (os-path-join "~" "a" "/b" "c")
"/b/c"

string-suffix-p n'existe pas avant Emacs 24.4 J'ai donc écrit le mien à Vérifier si une chaîne se termine par un suffixe en Emacs Lisp .

1 votes

Ce n'est pas portable, n'est-ce pas ? Il utilise le slash avant comme séparateur de répertoire et suppose une racine qui commence par un slash.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X