暗无天日

=============>DarkSun的个人博客

Emacs文件管理神器--dired常用操作说明

进入Dired

有几种方式都能够进入Dired:

  • 直接运行 M-x dired, 然后输入要定位到的哪个目录的路径就行了.

    默认情况下,Emacs会将当前buffer的 default-directory 作为默认要进入的目录.

    你在更改目录路径时随时可以按下 TAB 进行路径补全.

    dired允许进入远程服务器上的目录,只要输入的路径符合tramp规范即可.

  • 按下快捷键 C-x d, 它的效果与直接运行 M-x dired 一样.

    但同时还有一个快捷键 C-x 4 d, 它的作用是新开一个window,并在新开的那个window中进入dired buffer.

  • 可以像打开文件一样用 C-x C-f 打开一个目录,Emacs会自动调用dired来打开该目录.
  • 若使用了 ido,或者 helm 这样的插件,那么在用 C-x C-f 打开文件时按下 C-d 就会进入所在的目录了.

一个dired buffer看起来是这样的:

screenshot-20161210-204904.png

常用操作

导航操作

在dired buffer中可以用 n, p, C-n, C-p, <down>, <up> 将光标在各文件/目录间跳转.

当在目录上按下回车键后,会用dired新打开那个目录,而若是在文件上按下回车,则表示用Emacs打开该文件.

除了在 .. 目录上按下回车这种方式可以跳转到上层目录外,dired还提供了一个 ^ 快捷键可以快速地跳转到上层目录中.

另外,在dired buffer中,也能像在普通buffer中那样,使用Emacs的搜索命令来快速定位到指定文件处,这对在含有大量文件的目录中查找指定文件时非常有用.

若你用dired打开某个目录后又手工在Emacs之外对该目录进行了一些操作,比如新增或删除一些文件,dired默认并不会自动刷新内容,这时你可以按下 g 键来强制刷新dired buffer.

选择文件

在dired中,若你需要一次性操作操作文件或者目录,那么你往往需要先mark那些文件/目录,然后再按下对应的操作快捷键对这些文件进行操作.

常见的mark命令有这么几个:

m
mark光标所偶再的文件/目录,并将光标下移一行
DEL
删除上一行的mark标记,并将光标上移一行
u
unmark光标所偶再的文件/目录
U
unmark所有文件/目录
d
对于要删除的文件/目录进行标记比较特殊,需要用d键来为该文件添加flag,并将光标下移一行
t
反选所有文件的mark标记
#
选中所有以 # 结尾的文件,这些文件一般是Emacs自动保存的临时文件
~
选中所有以 ~ 结尾的文件,这些文件一般是Emacs自动备份的文件
* m
mark选中区域中的所有文件/目录
* u
unmark选中区域中的所有文件/目录
* t
反选区域内文件的mark标记
% m
mark所有匹配正则表达式的文件
% d
为所有匹配正则表达式的文件添加待删除的flag

操作文件/目录

由于在dired中的操作并不严格区分文件和目录,因此下面统一用文件代替

当按下操作快捷键时,dired会根据是否有mark的文件来决定该操作是针对光标所在文件进行(当没有mark文件时)的还是针对那些被makr的文件的.

当操作是针对那些被mark的文件时,Emacs一般会列出受影响的文件并提示是否继续该操作.

dired中对文件的常用的操作有:

+
创建一个子目录
C
拷贝文件
R
重命名文件,或者说是移动文件
D
删除文件
O
更改文件所有者,chown
G
更改文件所属组,chgrp
M
更改文件的属性,chmod
T
更改文件时间戳
x
删除那些被加了删除flag的文件
c
压缩文件,Emacs会根据 dired-compress-files-alist 中配置的压缩包后缀名来决定该怎么压缩
Z
使用gzip压缩/解压缩文件,Emacs会根据后缀名猜测你是需要压缩还是解压缩

除了明确mark出要操作的文件外,还可以使用正则表达式来操作一批文件. 这类使用正则表达式来批量操作的命令一般以 % 号开头:

% C
拷贝正则匹配的文件
% R
移动正则匹配的文件
% m
mark正则匹配的文件
% d
给正则匹配的文件添加待删除的flag
% H
为正则匹配的文件添加硬链接
% S
为正则匹配的文件添加软链接
% g
标记那些内容中包含正则表达式内容的文件

这其中比较特殊的是 % g, 该命令是根据 文件内容而不是文件名称 来决定是否mark该文件的.

有时,我们可能需要在多个文件中进行搜索/替换操作,那么可以使用如下操作:

M-s a C-s
使用isearch逐一搜索mark的那些文件
A
根据正则表达式搜索文件,并列出所有匹配的行
Q
对mark的那些文件逐一进行正则替换

dired还允许你调用外部命令来操作文件,这提供了莫大的灵活性:

!
以同步的方式调用shell命令来操作文件,命令运行的工作目录就是dired的当前目录
&
以异步的方式调用shell命令来操作文件,命令运行的工作目录就是dired的当前目录

在输入shell命令操作文件时,可以使用 * 来代替文件列表,这时单独的 * 被替换成被操作的文件,每个文件用空格分隔. 如果需要在命令行中使用通配符 *,则你需要将之用 *"" 来代替,因为对于shell来说,它的作用与 * 一样,而由于 * 并不是独立的,因此不会被替换调.

此外,你还可以使用 . 来代替单个文件,这时单独的 . 被替换成被操作的单个文件,且针对每个文件都会执行一条shell命令.

而倘若输入的命令中并没有函数 * 或者 ., 则表示对每个文件都执行一次shell命令,且文件名被添加到命令的最后.

书签

Emacs还允许你将常用的目录加入书签中,这样你可以很方便的跳回这些目录中.

在dired buffer中按下 C-x r m 就能将当前目录加入到书签中. 默认书签名字就是目录的名称,当然你也可以选择自己喜欢的名字来保存.

然后按下 C-x r l 就能看到弹出一个名为 *Bookmark List* 的buffer,里面列出了所有的书签.

在书签列表中用 n, p,或者 <down>, <up> 将光标移动到要打开的目录处按下回车就会发现Emacs用dired打开那个目录了.

*Bookmark List** 中按下 d 可以为书签加上待删除的flag,然后按下 x 就能删掉这些书签了. 这点与dired的操作很类似.

Emacs的书签当然不仅仅这么简单,要了解更多Emacs书签推荐阅读aborn同学的"Emacs的书签功能介绍"

访问打包文件

需要说明的是,dired插件本身并不对tar包或者zip包这类打包文件进行特殊处理.

当Emacs打开tar文件时,会进入tar-mode,该mode将整个tar包模拟成了一个目录,并提供了类似dired的操作方式.

对这个tar包进行修改后可以保存这个Tar buffer,更新原来的tar文件.

值得说明的是,Emacs原生支持tar文件,它无需额外的tar程序支持.

类似的,Emacs打开zip,jar,arc,lzh,zoo这类文件时,会进入archive-mode,它将压缩包模拟成一个目录,并提供类似dired的操作方式.

不过这类文件需要调用外部解压程序来进行解压和操纵压缩包里面的文件.

关于这两个命令,推荐看看这篇文件 <Emacs直接编辑压缩打包文件>

批量改名与wired

如果只是进行文件名的大小写转换,那么dired提供了两个命令专门来实现这一行为:

% u
所选文件名称转换为大写形式
% l
所选文件名称转换为小写形式

然而如果要实现更灵活的批量改名,就需要用到dired的正则操作了.

还记得前面提到的 % R, % C, % H 以及 % S 吗?

这几个命令的界面与 replace-regexp 命令的界面是一样的.

当执行这几个命令时,Emacs会提示你先输入一个正则表达式,用于匹配要被操作的那些源文件名称(可以匹配不完整的文件名). 随后你需要再输入一个字符串用于表示目标文件的名称,其中在该字符串中可以使用 \& 表示原正则匹配中的整个匹配内容,用 \N 来表示第N个分组的匹配内容

举个例子,假设你想要将所有后缀为 txt 的文件改名为 org 文件,那么你可以这样操作:

按下 % R,输入 \.txt$ 回车,再输入 \.org$. Emacs会逐个文件地问你是否进行重命名,按 ! 表示对所有文件都执行该操作. 至此所有txt文件都被重命名为org文件了.

不过,使用正则操作虽然能够提供一定的灵活性,但是并没有充分利用Emacs强大的编辑功能. 这个时候就需要请我们的 wired-mode 出场了,它充分的将文件管理与Emacs强大的编辑能力整合起来了.

wdired

wdierd允许你通过编辑dired buffer的方式来操作文件.

在dired buffer中按下 C-x C-q 就会进入wdired-mode了. 这时你会发现dired buffer中的文件名部分变得可以编辑了(如果设置了 wdired-allow-to-change-permissions 为t,那么你还能编辑文件属性).

这时你可以使用Emacs的那些编辑功能任意编辑,将文件名称改成你想要的名字. 然后按下 C-c C-c 就会发现文件被重命名成你想要的名字了. 你还可以在文件名中添加路径,这样一来可以实现把文件移动到其他目录中去.

如果你把源文件名称删掉而不提供新名字的化,那么 C-c C-c 后这些文件会被添加上待删除的flag,你只需要再按下 x 就能删掉这些文件了.

若你对这次的改动不满意的话,也可以通过 C-c C-k 取消这次的修改.

文件夹的比较

使用命令 M-x dired-compare-directories 可以将当前目录与其他目录进行比较并标记出目录间不同的那些文件.

默认情况下dired只根据文件名称来判断文件是否不同. 但其实你可以提供一个任意复杂的lisp表达式来作为判断条件. 任何让该lisp表达式返回非nil的文件都被认为是不相同的. 在这个lisp表达式中可以使用变量 size1size2 来表示两个文件的大小, mtime1mtime2 来表示两个文件的modification time, fa1fa2 表示文件属性列表.

其中后缀为1的变量为当前buffer文件的信息,后缀为2的变量为另一个文件夹中文件的信息.

打开文件

dired提供了多种方式打开文件:

f / <RET> /e
打开光标所在的文件,会覆盖原dired buffer.
o / <mouse-1> / <mouse-2>
在新窗口中打开光标所在的文件,并不会覆盖原dired buffer.
v
以只读的方式打开光标所在的文件,会覆盖原dired buffer.

上面这些命令,都只会打开光标所在的文件(而不管是否已经mark了多个文件),而且都是使用Emacs本身来打开文件的.

不过Emacs本身支持文本文件,图片文件以及pdf文件,因此一般来说用Emacs打开文件也足够了.

若需要使用外部程序来打开文件,则需要使用 !& 命令. 一般来说,对于linux用户可以使用 xdg-open 这个程序来使用默认的打开方式打开文件.

Xah大神专门针对用外部程序打开文件写过一篇博文,有兴趣的同学可以看一下: Emacs:Open File in External App

dired-x插件

dired-x为dired增加了很多方便的功能,比较常用的有:

* .
mark指定后缀名的文件
F
打开mark的那些文件,每个文件一个window
C-u F
在后台打开mark的那些文件

此外dired-x也会增强原dired已有的功能:

在没有mark文件的情况下使用 !&,则Emacs会依据变量 dired-guess-shell-alist-default 中定义的规则来猜测你要对该文件作什么操作.

例如,针对tar文件按下 !, 它会自动帮你填上 tar xvf 命令.

其他高级用法

排序

细心的同学应该会注意到dired buffer中的内容其实就是 ls -l 产生的结果.

我们可以自定义传递给 ls 的参数以此产生排序的效果.

按下 C-u s,会在minibuffer中显示 ls switches (must contain -l): -al, 我们在这里修改传递给 ls 的参数.

修改参数为 -alS 表示结果会按照大小排序,修改参数为 -alSr 表示按大小逆向排序.

当然,由于按时间排序这个功能太常见了,你可以直接按 s 进行排序,按第一次按时间先后进行排序,再按一次则变成按时间先后逆向排序.

过滤

若需要过滤掉一些不关心的文件(比如.svn,.git文件夹等),可以先mark那些要隐藏的文件(可以使用正则表达式一次mark一批文件),然后按下 k 隐藏掉这些文件.

若大家觉得不方便的话,dired-x还提供了一个 dired-omit-mode,能够自动隐藏调你想屏蔽的文件.

在启动 dired-omit-mode 前,你通常需要配置一下 dired-omit-filesdired-omit-extensions 这两个变量.

其中 dired-omit-files 是一个正则表达式,任何名称匹配该正则表达式的文件将被隐藏.

dired-omit-extensions 则是一个字符串列表,任何文件后缀在这个列表中的文件也都会被隐藏.

分色

分色是指让不同类型的文件用不同颜色标注出来.

虽然dired本身并不支持分色,但是借助 highlight-lines-matching-regexp 命令,我们很容易可以实现该功能.

假设我们想把所有org文件用黄色标注出来,那么可以这样做:

  1. 运行 M-s h l 或者 M-x highlight-lines-matching-regexp
  2. 输入正则表达式 \.org$
  3. 输入标注作色的face hi-yellow

当然你也可以通过 dired-mode-hook 让这一分色过程自动化:

(add-hook 'dired-mode-hook
          (lambda ()
            (highlight-lines-matching-regexp "\.org$" 'hi-yellow)))

这样一来,每次进入dired,都会自动将org文件标注为黄色.

screenshot-20161210-205044.png

跨目录操作

若同时想对多个目录下的文件进行操作该怎么办呢?

在目录上按下 I 快捷键就能将该子目录的内容插入到当前同一个dired buffer中.

例如: 假设我有这么一个文件夹:

/home/lujun9972/github/lujun9972.github.com/Emacs之怒/  /home/Administrator/lujun9972.github.com:
  总用量 117
  drwxr-xr-x+ 1 Administrator None     0 十二  8 15:50 .
  drwxrwxrwx+ 1 Administrator None     0 十二  8 15:50 ..
  drwxr-xr-x+ 1 Administrator None     0 十二  8 15:29 .git
  -rw-r--r--  1 Administrator None   187 十一 24 17:36 .travis.yml
  -rw-r--r--  1 Administrator None    80 十一 24 17:36 about.org
  drwxr-xr-x+ 1 Administrator None     0 十二  8 15:48 Emacs之怒
  drwxr-xr-x+ 1 Administrator None     0 十二  5 12:58 linux和它的小伙伴
  -rw-r--r--  1 Administrator None   238 十一 24 17:36 README
  -rw-r--r--  1 Administrator None 61440 十二  8 15:18 test.tar
  drwxr-xr-x+ 1 Administrator None     0 十一 24 17:36 编程之旅
  lrwxrwxrwx  1 Administrator None    36 十一 24 17:36 读书笔记 -> /home/lujun9972/我的笔记/Reading
  drwxr-xr-x+ 1 Administrator None     0 十一 24 17:36 时间管理
  drwxr-xr-x+ 1 Administrator None     0 十一 24 17:36 无主之地

当我将光标移动到 Emacs之怒 上然后按下 i 键时,就变成了:

/home/Administrator/lujun9972.github.com:
总用量 117
drwxr-xr-x+ 1 Administrator None     0 十二  8 15:50 .
drwxrwxrwx+ 1 Administrator None     0 十二  8 15:50 ..
drwxr-xr-x+ 1 Administrator None     0 十二  8 15:29 .git
-rw-r--r--  1 Administrator None   187 十一 24 17:36 .travis.yml
-rw-r--r--  1 Administrator None    80 十一 24 17:36 about.org
drwxr-xr-x+ 1 Administrator None     0 十二  8 15:48 Emacs之怒
drwxr-xr-x+ 1 Administrator None     0 十二  5 12:58 linux和它的小伙伴
-rw-r--r--  1 Administrator None   238 十一 24 17:36 README
-rw-r--r--  1 Administrator None 61440 十二  8 15:18 test.tar
drwxr-xr-x+ 1 Administrator None     0 十一 24 17:36 编程之旅
lrwxrwxrwx  1 Administrator None    36 十一 24 17:36 读书笔记 -> /home/lujun9972/我的笔记/Reading
drwxr-xr-x+ 1 Administrator None     0 十一 24 17:36 时间管理
drwxr-xr-x+ 1 Administrator None     0 十一 24 17:36 无主之地

/home/Administrator/lujun9972.github.com/Emacs之怒:
总用量 77
drwxr-xr-x+ 1 Administrator None     0 十二  8 16:03 .
lrwxrwxrwx  1 Administrator None    33 十二  8 16:03 .#dired的常用操作.org -> Administrator@PC201505171055.5772
drwxr-xr-x+ 1 Administrator None     0 十二  8 15:50 ..
-rw-r--r--  1 Administrator None  6981 十二  8 16:02 dired的常用操作.org
-rw-r--r--  1 Administrator None  9213 十一 24 17:36 Emacs查看日志常用命令.org
-rw-r--r--  1 Administrator None 10881 十一 24 17:36 Emacs中那些不常用的行操作命令.org
-rw-r--r--  1 Administrator None  5507 十一 24 17:36 Emacs作为图片浏览器.org
-rw-r--r--  1 Administrator None  3226 十一 24 17:36 tramp的一般用法.org
-rw-r--r--  1 Administrator None  2522 十一 24 17:36 判断Emacs是否在图形环境中的正确方法.org
-rw-r--r--  1 Administrator None 11115 十一 29 11:30 如何编写EmacsScript.org
-rw-r--r--  1 Administrator None  1524 十一 24 17:36 使用Emacs ediff作为git diff工具.org
-rw-r--r--  1 Administrator None  1791 十一 24 17:36 使用Emacs ediff作为git merge工具.org

这样一来你就可以同时操作多个目录中的文件了.

你还可以使用 $ 来将目录折叠/舒展开来,dired中的那些命令会忽略调折叠起来的内容.

例如我在 lujun9972.github.com 目录内容中的任意位置处按下 $,则会发现dired buffer变成了

/home/Administrator/lujun9972.github.com:...
/home/Administrator/lujun9972.github.com/Emacs之怒:
总用量 77
drwxr-xr-x+ 1 Administrator None     0 十二  8 16:03 .
lrwxrwxrwx  1 Administrator None    33 十二  8 16:03 .#dired的常用操作.org -> Administrator@PC201505171055.5772
drwxr-xr-x+ 1 Administrator None     0 十二  8 15:50 ..
-rw-r--r--  1 Administrator None  6981 十二  8 16:02 dired的常用操作.org
-rw-r--r--  1 Administrator None  9213 十一 24 17:36 Emacs查看日志常用命令.org
-rw-r--r--  1 Administrator None 10881 十一 24 17:36 Emacs中那些不常用的行操作命令.org
-rw-r--r--  1 Administrator None  5507 十一 24 17:36 Emacs作为图片浏览器.org
-rw-r--r--  1 Administrator None  3226 十一 24 17:36 tramp的一般用法.org
-rw-r--r--  1 Administrator None  2522 十一 24 17:36 判断Emacs是否在图形环境中的正确方法.org
-rw-r--r--  1 Administrator None 11115 十一 29 11:30 如何编写EmacsScript.org
-rw-r--r--  1 Administrator None  1524 十一 24 17:36 使用Emacs ediff作为git diff工具.org
-rw-r--r--  1 Administrator None  1791 十一 24 17:36 使用Emacs ediff作为git merge工具.org

你会发现 lujun9972.github.com 中的内容被简化成了 ...

如果你希望把某个子目录给删掉,可以在子目录的头部按下 C-u k,你会发现内容变成了:

/home/lujun9972/github/lujun9972.github.com/Emacs之怒:
/home/Administrator/lujun9972.github.com:...

子目录的内容都被删除了.