Supposons que je dispose de variables dir
et file
contenant des chaînes représentant respectivement un répertoire et un nom de fichier. Quelle est la manière appropriée dans emacs lisp de les joindre dans un chemin complet vers le fichier?
Par exemple, si dir
est "/usr/bin"
et si le 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 répétition de barre oblique.
En parcourant le manuel pour les 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 peuvent être syntaxiquement incorrects ou faire référence au mauvais fichier.
Si vous souhaitez utiliser un nom de fichier de répertoire pour créer une telle combinaison, vous devez d’abord le convertir en nom de répertoire en utilisant
file-name-as-directory
:(concat (file-name-as-directory dirfile) relfile)
N’essayez pas de concaténer une barre oblique à la main, comme dans
;;; Wrong! (concat dirfile "/" relfile)
parce que ce n’est pas portable. Toujours utiliser
file-name-as-directory
.
Les autres commandes utiles sont: file-name-directory
file-name-nondirectory
, file-name-nondirectory
et autres dans la section Composants de nom de fichier .
Vous pouvez utiliser expand-file-name
pour ceci:
(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épertoires absolus. Je pense que la réponse de Trey est la solution préférable.
Je voulais joindre plusieurs répertoires nesteds sur un chemin. A l’origine, j’ai utilisé plusieurs appels expand-file-name
, comme ceci:
(expand-file-name "b" (expand-file-name "a" "/tmp")) "/tmp/a/b"
Cependant, c’est plutôt verbeux et lit à l’envers.
Au lieu de cela, j’ai écrit une fonction qui agit comme os.path.join
de Python:
(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 ça:
(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"
Si vous utilisez une bibliothèque pratique de manipulation de fichiers et de répertoires, vous n’avez besoin que de f-join
. Le code ci-dessous est pour 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 ((ssortingng-prefix-p "/" p) (setq path p)) ((or (not path) (ssortingng-suffix-p "/" p)) (setq path (concat path p))) (t (setq path (concat path "/" p)))))) path))
Cela se comporte exactement comme os.path.join
de Python.
ELISP> (os-path-join "~" "a" "b" "") "~/a/b/" ELISP> (os-path-join "~" "a" "/b" "c") "/b/c"
ssortingng-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 dans Emacs Lisp .
Voici ce que j’utilise:
(defun catdir (root &rest dirs) (apply 'concat (mapcar (lambda (name) (file-name-as-directory name)) (push root dirs))))
Différences de @ dbr’s:
root
est relatif (voir notes) root
comme racine, alors que joindirs
utilisera le premier composant commençant par "/"
comme racine. Remarques
De nombreuses fonctions de traitement de fichiers (toutes, la plupart, ???) normaliseront les barres obliques redondantes et appeleront expand-file-name
(ou similaire) sur des chemins relatifs, donc # 2 et # 3 n’ont pas vraiment d’importance.