16

该函数也directory-files返回...条目。虽然从某种意义上说,只有这样函数才能返回所有现有条目,但我还没有看到包含这些条目的用途。另一方面,每次使用时directory-files我也会写一些类似的东西

(unless (string-match-p "^\\.\\.?$" ... 

或为了提高效率

(unless (or (string= "." entry)
            (string= ".." entry))
   ..)

特别是在交互式使用中 ( M-:),额外的代码是不可取的。

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

4

3 回答 3

21

您可以将其作为原始函数调用的一部分来执行。

(directory-files DIRECTORY &optional FULL MATCH NOSORT)

If MATCH is non-nil, mention only file names that match the regexp MATCH.

所以:

(directory-files (expand-file-name "~/") nil "^\\([^.]\\|\\.[^.]\\|\\.\\..\\)")

或者:

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

尽管更类似于您自己的方法的东西可能会成为更有效的包装器,真的。

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

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

(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)))
于 2013-06-18T09:19:00.043 回答
9

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

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

(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选项将绝对路径传递给目录,那么您将获得立即文件和子目录的绝对路径列表,根据如何在 linux 中列出文件及其绝对路径?. 有关路径构造的说明,请参见在 Elisp 中,如何正确插入斜线的路径字符串?.

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

于 2014-03-13T09:41:21.603 回答
1

只是使用怎么样remove-if

(remove-if (lambda (x) (member x '("." "..")))
           (directory-files path))
于 2021-12-14T04:58:58.480 回答