掌握 Linux ls 命令

Linux 的 ls 命令有大量的选项,可以提供有关文件的重要信息。
203 位读者喜欢这个。
Why the operating system matters even more in 2017

互联网档案图书图片。由 Opensource.com 修改。 CC BY-SA 4.0

ls 命令列出 POSIX 系统上的文件。 这是一个简单的命令,经常被低估,不是因为它能做什么(因为它确实只做一件事),而是你如何优化它的使用。

在 10 个最重要的终端命令中,不起眼的 ls 命令排在前三位,因为 ls 不 *只是* 列出文件,它还会告诉你关于文件的重要信息。 它会告诉你谁拥有文件或目录,每个文件何时丢失或修改,甚至是什么类型的文件。 然后是它的偶然功能,让你感觉到你在哪里,附近有什么东西,以及你可以用它们做什么。

如果你的 ls 经验仅限于你的发行版在 .bashrc 中对其进行的别名设置,那么你可能错过了一些东西。

GNU 还是 BSD?

在了解 ls 的隐藏功能之前,你必须确定你正在运行哪个 ls 命令。 两个最流行的版本是 GNU 版本,包含在 GNU coreutils 包中,以及 BSD 版本。 如果你正在运行 Linux,那么你可能已经安装了 ls。 如果你正在运行 BSD 或 MacOS,那么你拥有 BSD 版本。 这两者之间存在差异,本文对此进行了说明。

你可以使用 --version 选项找出你电脑上的是哪个版本

$ ls --version

如果这返回关于 GNU coreutils 的信息,那么你拥有 GNU 版本。 如果它返回一个错误,你可能正在运行 BSD 版本(运行 man ls | head 来确定)。

你还应该调查你的发行版可能已经设置了哪些预设。 对终端命令的自定义通常放置在 $HOME/.bashrc$HOME/.bash_aliases$HOME/.profile 中,它们通过将 ls 别名为更复杂的 ls 命令来实现。 例如

alias ls='ls --color'

发行版提供的预设非常有用,但它们确实使人们难以辨别 ls 本身的功能以及它的附加选项提供了什么。 如果你想要运行 ls 而不是别名,你可以使用反斜杠 "转义" 该命令

$ \ls

分类

单独运行时,ls 只是在终端中以尽可能多的列数来列出文件

$ ls ~/example
bunko        jdk-10.0.2
chapterize   otf2ttf.ff
despacer     overtar.sh
estimate.sh  pandoc-2.7.1
fop-2.3      safe_yaml
games        tt

这是有用的信息,但如果没有图标的便利来快速传达哪个是目录,哪个是文本文件,哪个是图像等等,所有这些文件看起来基本上都相同。

使用 -F(或 GNU 上的 --classify)在每个条目后显示指示符,以标识文件类型

$ ls ~/example
bunko         jdk-10.0.2/
chapterize*   otf2ttf.ff*
despacer*     overtar.sh*
estimate.sh   pandoc@
fop-2.3/      pandoc-2.7.1/
games/        tt*

使用此选项,终端中列出的项目按文件类型分类,使用以下简写

  • 斜杠 (/) 表示目录(或“文件夹”)。
  • 星号 (*) 表示可执行文件。 这包括二进制文件(编译代码)以及脚本(具有可执行权限的文本文件)。
  • at 符号 (@) 表示符号链接(或“别名”)。
  • 等号 (=) 表示套接字。
  • 在 BSD 上,百分号 (%) 表示白化(某些文件系统上删除文件的一种方法)。
  • 在 GNU 上,尖括号 (>) 表示门(Illumos 和 Solaris 上的进程间通信)。
  • 竖线 (|) 表示 FIFO

此选项的更简单版本是 -p,它仅区分文件和目录。

长列表

ls 获取 "长列表" 非常常见,以至于许多发行版将 ll 别名为 ls -l。 长列表格式提供了许多重要的文件属性,例如权限、拥有每个文件的用户、文件所属的组、文件大小(以字节为单位)以及文件上次更改的日期

$ ls -l
-rwxrwx---. 1 seth users         455 Mar  2  2017 estimate.sh
-rwxrwxr-x. 1 seth users         662 Apr 29 22:27 factorial
-rwxrwx---. 1 seth users    20697793 Jun 29  2018 fop-2.3-bin.tar.gz
-rwxrwxr-x. 1 seth users        6210 May 22 10:22 geteltorito
-rwxrwx---. 1 seth users         177 Nov 12  2018 html4mutt.sh
[...]

如果你不喜欢以字节为单位思考,请添加 -h 标志(或 GNU 中的 --human)以将文件大小转换为更人性化的表示法

$ ls --human
-rwxrwx---. 1 seth users    455 Mar  2  2017 estimate.sh
-rwxrwxr-x. 1 seth seth     662 Apr 29 22:27 factorial
-rwxrwx---. 1 seth users    20M Jun 29  2018 fop-2.3-bin.tar.gz
-rwxrwxr-x. 1 seth seth    6.1K May 22 10:22 geteltorito
-rwxrwx---. 1 seth users    177 Nov 12  2018 html4mutt.sh

你可以通过仅显示所有者列(使用 -o)或仅显示组列(使用 -g)来查看更少的信息

$ ls -o
-rwxrwx---. 1 seth    455 Mar  2  2017 estimate.sh
-rwxrwxr-x. 1 seth    662 Apr 29 22:27 factorial
-rwxrwx---. 1 seth    20M Jun 29  2018 fop-2.3-bin.tar.gz
-rwxrwxr-x. 1 seth   6.1K May 22 10:22 geteltorito
-rwxrwx---. 1 seth    177 Nov 12  2018 html4mutt.sh

组合这两个选项以显示两者都不显示。

时间和日期格式

ls 的长列表格式通常如下所示

-rwxrwx---. 1 seth users         455 Mar  2  2017 estimate.sh
-rwxrwxr-x. 1 seth users         662 Apr 29 22:27 factorial
-rwxrwx---. 1 seth users    20697793 Jun 29  2018 fop-2.3-bin.tar.gz
-rwxrwxr-x. 1 seth users        6210 May 22 10:22 geteltorito
-rwxrwx---. 1 seth users         177 Nov 12  2018 html4mutt.sh

月份的名称不易排序,无论是在计算上还是(取决于你的大脑是倾向于字符串还是整数)通过识别。 你可以使用 --time-style 选项加上格式名称来更改时间戳的格式。 可用格式为

  • full-iso (1970-01-01 21:12:00)
  • long-iso (1970-01-01 21:12)
  • iso (01-01 21:12)
  • locale (使用你的区域设置)
  • posix-STYLE(用区域定义替换 STYLE)

你还可以使用 date 命令的正式表示法创建自定义样式。

按时间排序

通常,ls 命令按字母顺序排序。 你可以使用 -t 选项使其根据哪个文件最近被更改(最新的文件首先列出)进行排序。

例如

$ touch foo bar baz
$ ls
bar  baz  foo
$ touch foo
$ ls -t 
foo bar baz

列表类型

ls 的标准输出在可读性与空间效率之间取得平衡,但有时你希望文件列表采用特定的排列方式。

对于以逗号分隔的文件列表,请使用 -m

ls -m ~/example
bar, baz, foo

要强制每行一个文件,请使用 -1 选项(这是数字 1,不是小写字母 L)

$ ls -1 ~/bin/
bar
baz
foo

要按文件扩展名而不是文件名对条目进行排序,请使用 -X(这是大写字母 X)

$ ls
bar.xfc  baz.txt  foo.asc
$ ls -X 
foo.asc  baz.txt  bar.xfc

隐藏杂乱

在某些 ls 列表中,你可能不关心一些条目。 例如,元字符 ... 分别表示“此处”和“返回上一级”。 如果你熟悉在终端中导航,你可能已经知道每个目录都将自身称为 . 并将其父目录称为 ..,因此当你使用 -a 选项显示隐藏文件时,不需要不断地提醒它。

要显示几乎所有隐藏文件(排除 ...),请使用 -A 选项

$ ls -a
.
.. 
.android
.atom
.bash_aliases
[...]
$ ls -A
.android
.atom
.bash_aliases
[...]

对于许多优秀的 Unix 工具,有一种通过在要保存的文件名后附加一些特殊字符来保存备份文件的传统。 例如,在 Vim 中,备份文件以 ~ 字符附加到名称来保存。

这些类型的备份文件在很多场合中将我从愚蠢的错误中拯救出来,但在享受它们提供的安全感多年之后,我感觉不需要有视觉证据表明它们存在。 我相信 Linux 应用程序会生成备份文件(如果它们声称这样做),我很乐意相信它们的存在。

要隐藏备份文件不被查看,请使用 -B--ignore-backups 来隐藏常见的备份格式(此选项在 BSD ls 中不可用)

$ ls
bar.xfc  baz.txt  foo.asc~  foo.asc
$ ls -B 
bar.xfc  baz.txt  foo.asc

当然,备份文件仍然存在; 它只是被过滤掉,以便你不必查看它。

GNU Emacs 保存备份文件(除非另有配置)的文件名的开头和结尾都有一个哈希字符 (#) (#file#)。 其他应用程序可能会使用不同的样式。 使用什么模式无关紧要,因为你可以使用 --hide 选项创建自己的排除项

$ ls
bar.xfc  baz.txt  #foo.asc#  foo.asc
$ ls --hide="#*#"
bar.xfc  baz.txt  foo.asc

递归列出目录

除非你专门在目录上运行 ls,否则目录的内容不会与 ls 命令一起列出

$ ls -F 
example/  quux*  xyz.txt
$ ls -R
quux  xyz.txt

./example:
bar.xfc  baz.txt  #foo.asc#  foo.asc

使用别名使其永久

ls 命令可能是任何给定 shell 会话期间最常使用的命令。 它是你的眼睛和耳朵,为你提供上下文并确认命令的结果。 虽然拥有很多选项很有用,但 ls 的部分美妙之处在于它的简洁:两个字符和回车键,你就确切地知道你在哪里以及附近有什么。 如果你必须停下来思考(更不用说键入)几个不同的选项,它就会变得不那么方便,因此通常即使是最有用的选项也会被省略。

解决方案是别名你的 ls 命令,以便在使用它时,你可以获得你最关心的信息。

要在 Bash shell 中为命令创建别名,请在你的主目录中创建一个名为 .bash_aliases 的文件(你必须在开头包含点)。 在此文件中,列出你要为其创建别名的命令,然后列出你要创建的别名。 例如

alias ls='ls -A -F -B --human --color'

此行导致你的 Bash shell 将 ls 命令解释为 ls -A -F -B --human --color

你不仅限于重新定义现有命令。 你可以创建自己的别名

alias ll='ls -l'
alias la='ls -A'
alias lh='ls -h'

为了使别名起作用,你的 shell 必须知道 .bash_aliases 配置文件存在。 在编辑器中打开 .bashrc 文件(如果不存在则创建它),并包含此代码块

if [ -e $HOME/.bash_aliases ]; then
    source $HOME/.bash_aliases
fi

每次加载 .bashrc 时(也就是每次启动新的 Bash shell 时),Bash 都会将 .bash_aliases 加载到你的环境中。 你可以关闭并重新启动你的 Bash 会话,或者只是强制它现在这样做

$ source ~/.bashrc

如果你忘记是否已经别名了一个命令,which 命令会告诉你

$ which ls
alias ls='ls -A -F -B --human --color'
	/usr/bin/ls

如果你已经使用选项将 ls 命令别名到自身,你可以随时通过在 ls 前面加上反斜杠来覆盖你自己的别名。 例如,在示例别名中,备份文件使用 -B 选项隐藏,这意味着无法使用 ls 命令备份文件。 覆盖别名以查看备份文件

$ ls
bar  baz  foo
$ \ls
bar  baz  baz~  foo

只做一件事,并做好它

ls 命令有大量的选项,其中许多选项是小众的或高度依赖于你使用的终端。 在 GNU 系统上查看 info ls 或在 GNU 或 BSD 系统上查看 man ls 以获取更多选项。

你可能会觉得奇怪,一个以每个工具“只做一件事,并且把它做好”为前提而闻名的系统,怎么会用 50 个选项来加重其最常用的命令。但 ls 确实只做一件事:它列出文件。并且凭借 50 个选项,让你可以控制接收列表的方式,ls 将它的本职工作完成得非常、非常出色。

接下来要读什么
标签
Seth Kenlon
Seth Kenlon 是一位 UNIX 极客、自由文化倡导者、独立多媒体艺术家和《龙与地下城》爱好者。他曾在电影和计算行业工作,而且经常同时从事这两项工作。

12 条评论

写得好,Seth!我学到了几个(对我来说)新的 ls 选项,并且回忆起几个我有一段时间没用过的选项。

很高兴你喜欢它!我觉得很多人都只是接受 ``ls`` 的现状,或者接受发行版提供给我们的状态。但我喜欢它具有如此高的可定制性。

回复 ,作者是 ScottNesbitt

也许是最常用的命令之一!这是一篇令人耳目一新的文章,它鼓励人们多学习一点!谢谢,Seth。

你说得没错。我认为最终让我决定使用 Dvorak 键盘的原因之一是打字``ls``非常容易(Qwerty 键盘上的 "p;" 键)。

回复 ,作者是 marco.bravo

一如既往的精彩文章,你教了我一些新东西。

是的,我非常喜欢研究这些基本命令,这些我们认为理所当然的命令。有时它们确实 *只是* 基本的简单命令,但有时它们会给你带来惊喜。

回复 ,作者是 Don Watkins

很久以前我就标准化了

alias l="ls -CF"

将该过程缩短为一个字符。我认为现在许多默认的 ls 实现都默认采用柱状格式。

需要注意的一个烦恼是 "ls" 基于区域设置的不同排序行为,以及 "en_US.UTF-8" 和旧式 "C" 之间的差异。我从来没有研究过原因,但 en_US.UTF-8 区域设置似乎忽略了使用 'ls -a' 生成的文件名中的 '.' 字符,并将它们与可见文件交错排序,并且还将大写和小写字母组合在一起。我更喜欢 C 样式的输出,它将大写和小写字母分开排序,并将隐藏文件在顶部组合在一起(bash:export LANG=C)。

即使是最基本的实用程序也能让人耳目一新,谢谢!

有趣的是,你不喜欢 en_US.UTF8 排序的行为。我不知何故从未注意到它,但现在你指出来,我相信我更喜欢它,因为通常当我寻找,比如说,.emacs.d 时,我将其视为以 |e| 开头,即使它实际上以一个点开头。萝卜青菜各有所爱!

我很好奇是什么导致了这种行为。(不过,我没有好奇到去获取源代码并查找,因为否则我就有答案了!)

感谢您的评论!

回复 ,作者是 JamesF

我也一直不喜欢 en_US.UTF-8 排序。就我个人而言,我使用 LC_COLLATE=C,并将其他区域设置保留为 en_US.UTF-8。

回复 ,作者是 JamesF

我喜欢这篇文章

这是一篇很棒的文章。我一年前开始使用 Linux,并且我百看不厌。它可以完成我需要它完成的一切,并且我迫不及待地想学习更多!

Creative Commons License本作品采用知识共享署名-相同方式共享 4.0 国际许可协议进行许可。
© . All rights reserved.