Emacs lisp:`directory-files`

kdb*_*kdb 13 directory emacs elisp interactive file

该函数还directory-files返回...条目.虽然在某种意义上确实如此,只有这种方式函数返回所有现有条目,我还没有看到包含这些条目的用途.另一方面,每次使用directory-files我也会写一些类似的东西

(unless (string-match-p "^\\.\\.?$" ... 
Run Code Online (Sandbox Code Playgroud)

或者为了提高效率

(unless (or (string= "." entry)
            (string= ".." entry))
   ..)
Run Code Online (Sandbox Code Playgroud)

特别是在交互式使用(M-:)中,额外的代码是不希望的.

是否有一些预定义的函数只能有效地返回目录的实际子条目?

phi*_*ils 17

您可以将此作为原始函数调用的一部分.

(directory-files DIRECTORY &optional FULL MATCH NOSORT)

If MATCH is non-nil, mention only file names that match the regexp MATCH.
Run Code Online (Sandbox Code Playgroud)

所以:

(directory-files (expand-file-name "~/") nil "^\\([^.]\\|\\.[^.]\\|\\.\\..\\)")
Run Code Online (Sandbox Code Playgroud)

要么:

(defun my-directory-files (directory &optional full nosort)
  "Like `directory-files' with MATCH hard-coded to exclude \".\" and \"..\"."
  (directory-files directory full "^\\([^.]\\|\\.[^.]\\|\\.\\..\\)" nosort))
Run Code Online (Sandbox Code Playgroud)

虽然更类似于你自己的方法可能会使一个更有效的包装,真的.

(defun my-directory-files (directory &optional full match nosort)
  "Like `directory-files', but excluding \".\" and \"..\"."
  (delete "." (delete ".." (directory-files directory full match nosort))))
Run Code Online (Sandbox Code Playgroud)

虽然那是两次处理列表,但我们知道我们希望排除的每个名称只有一个实例(并且它们很可能会首先出现),所以更像这样的东西可能是一个很好的解决方案,如果你是期望经常处理大型目录:

(defun my-directory-files (directory &optional full match nosort)
  "Like `directory-files', but excluding \".\" and \"..\"."
  (let* ((files (cons nil (directory-files directory full match nosort)))
         (parent files)
         (current (cdr files))
         (exclude (list "." ".."))
         (file nil))
    (while (and current exclude)
      (setq file (car current))
      (if (not (member file exclude))
          (setq parent current)
        (setcdr parent (cdr current))
        (setq exclude (delete file exclude)))
      (setq current (cdr current)))
    (cdr files)))
Run Code Online (Sandbox Code Playgroud)

  • 您可以使用`(directory-files"〜/"t directory-files-no-dot-files-regexp)获得相同的结果. (6认同)
  • @squiter你的答案是最好的,但没有人看到它。 (2认同)

Mir*_*lov 7

如果f.el使用方便的文件和目录操作库,则只需要功能f-entries.

但是,如果您出于某种原因不想使用此库,并且您可以使用非便携式*nix解决方案,则可以使用ls命令.

(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)))
Run Code Online (Sandbox Code Playgroud)

上面的代码就足够了,但需要进一步解释.

摆脱点

根据man ls:

   -A, --almost-all
          do not list implied . and ..
Run Code Online (Sandbox Code Playgroud)

通过split-string用空格分割字符串,我们可以解析ls输出:

(split-string (shell-command-to-string "ls -A"))
Run Code Online (Sandbox Code Playgroud)

文件名中的空格

问题是某些文件名可能包含空格.split-string通过在可变由正则表达式默认分割split-string-default-separators,这是"[ \f\t\n\r\v]+".

   -1     list one file per line
Run Code Online (Sandbox Code Playgroud)

-1允许按换行符分隔文件,"\n"作为唯一的分隔符传递.您可以将它包装在一个函数中,并将其与任意目录一起使用.

(split-string (shell-command-to-string "ls -A1") "\n")
Run Code Online (Sandbox Code Playgroud)

递归

但是如果你想递归地潜入子目录,返回文件以备将来使用呢?如果您只是更改目录和问题ls,您将获得没有路径的文件名,因此Emacs不会知道这些文件的位置.一种解决方案是ls始终返回绝对路径.根据man ls:

   -d, --directory
          list directory entries instead of contents, and do not dereference symbolic links
Run Code Online (Sandbox Code Playgroud)

如果你使用通配符和-d选项传递绝对路径到目录,那么你将获得一个直接文件和子目录的绝对路径列表,根据我如何在linux中列出其绝对路径的文件?.有关路径构造的说明,请参阅In Elisp,如何获取正确插入斜杠的路径字符串?.

(let ((path (file-name-as-directory (expand-file-name d))))
  (split-srting (shell-command-to-string (concat "ls -A1d " path "*")) "\n"))
Run Code Online (Sandbox Code Playgroud)

省略空字符串

Unix命令必须添加一个尾随空格来输出,以便提示位于新行.否则代替:

user@host$ ls
somefile.txt
user@host$
Run Code Online (Sandbox Code Playgroud)

那里将会是:

user@host$ ls
somefile.txtuser@host$
Run Code Online (Sandbox Code Playgroud)

当您将自定义分隔符传递给split-string它时,它会将此换行符视为一行.通常,这允许正确解析CSV文件,其中空行可能是有效数据.但是ls我们最终得到一个空字符串,应该通过传递t第三个参数来省略split-string.

  • 这不是最好的答案,最好的答案是下面的 `(directory-files "/tmp" t directory-files-no-dot-files-regexp)` (2认同)