繁体   English   中英

Emacs lisp:简洁的方法来获取不带“.”的`directory-files` 和 ”..”?

[英]Emacs lisp: Concise way to get `directory-files` without "." and ".."?

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

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

或者为了更好的效率

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

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

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

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

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

如果你使用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的正则表达式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来省略它。

只使用remove-if怎么样?

(remove-if (lambda (x) (member x '("." "..")))
           (directory-files path))

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM