如果你使用f.el,一个方便的文件和目录操作库,你只需要函数f-entries。
但是,如果您出于某种原因不想使用此库,并且可以使用非便携式 *nix 解决方案,则可以使用 ls command。
(defun my-directory-files (d)
(let* ((path (file-name-as-directory (expand-file-name d)))
(command (concat "ls -A1d " path "*")))
(split-string (shell-command-to-string command) "\n" t)))
上面的代码就足够了,但是为了解释,请继续阅读。
去除点
根据man ls:
-A, --almost-all
do not list implied . and ..
split-string 用空格分割字符串,我们可以解析ls 输出:
(split-string (shell-command-to-string "ls -A"))
文件名中的空格
问题是某些文件名可能包含空格。 split-string 默认由变量split-string-default-separators 中的正则表达式拆分,即"[ \f\t\n\r\v]+"。
-1 list one file per line
-1 允许用换行符分隔文件,将"\n" 作为唯一分隔符传递。您可以将其包装在一个函数中并与任意目录一起使用。
(split-string (shell-command-to-string "ls -A1") "\n")
递归
但是,如果您想递归地深入到子目录,返回文件以供将来使用,该怎么办?如果您只是更改目录并发出ls,您将获得没有路径的文件名,因此 Emacs 不会知道这些文件的位置。一种解决方案是让ls 始终返回绝对路径。根据man ls:
-d, --directory
list directory entries instead of contents, and do not dereference symbolic links
如果您使用通配符和-d 选项将绝对路径传递到目录,那么您将根据How can I list files with their absolute path in linux? 获得直接文件和子目录的绝对路径列表。路径构造的解释见In Elisp, how to get path string with slash properly inserted?。
(let ((path (file-name-as-directory (expand-file-name d))))
(split-srting (shell-command-to-string (concat "ls -A1d " path "*")) "\n"))
省略空字符串
Unix 命令必须在输出中添加尾随空格,以便提示位于新行。否则代替:
user@host$ ls
somefile.txt
user@host$
会有:
user@host$ ls
somefile.txtuser@host$
当您将自定义分隔符传递给split-string 时,它会将这个换行符单独视为一行。通常,这允许正确解析 CSV 文件,其中空行可能是有效数据。但是对于ls,我们最终会得到一个空字符串,应该通过将t 作为第三个参数传递给split-string 来省略它。