diff --git a/docs/Ch03/index.md b/docs/Ch03/index.md index 16e64ce2..c8b71cce 100644 --- a/docs/Ch03/index.md +++ b/docs/Ch03/index.md @@ -488,6 +488,53 @@ Ubuntu 官方源位于国外,往往会有速度与延迟上的限制,可以 在 Linux 在进行操作文件与目录是使用 Linux 最基础的一个技能。不像在 Windows 和 macOS 下有图形化界面,拖拽文件即可完成文件的移动,很容易管理文件与目录,Linux 的命令行操作虽然繁琐一些,但一旦上手,就可以通过命令与参数的组合完成通过图形化界面难以实现或者无法实现的功能。 +### 查看文件夹内容 {#ls} + +[第二章](../Ch02/index.md)已经介绍过 `ls` 的基本用法,这里再补充一些常用的选项。 + +```console +$ # -l 参数会以列表的形式输出文件的详细信息 +$ ls -l [DIRECTORY] +$ # -a 参数会显示所有文件,包括隐藏文件(以 . 开头的文件) +$ ls -a [DIRECTORY] +$ # -h 参数会以人类可读的方式显示文件大小,例如 1K、234M、2G 等 +$ ls -h [DIRECTORY] +``` + +!!! example "ls 示例" + + ```console title="以列表的形式显示当前目录下的所有文件(包括隐藏文件)" + $ ls -la + ``` + + ```console title="以人类可读的方式显示当前目录下的所有文件(包括隐藏文件)的详细信息" + $ ls -lha + ``` + +!!! tip "tree" + + `tree` 命令可以以树状图的形式显示目录结构,使用前需要先安装: + + ```console + $ sudo apt install tree + ``` + + 使用方法: + + ```console + $ tree [DIRECTORY] + ``` + +!!! tip "eza" + + [eza](https://github.com/eza-community/eza) 是一个 `ls` 的替代品,输出更加好看。可以使用如下命令安装: + + ```console + $ sudo apt install eza + ``` + + 其使用方法和 `ls` 基本相同,例如显示详细信息则使用 `eza -l`。 + ### 查看文件内容 {#view} #### cat {#cat} @@ -499,22 +546,32 @@ $ cat [OPTION] FILE !!! example "输出示例" - * 输出 file.txt 的全部内容 - - ```console - $ cat file.txt - ``` - - * 查看 file1.txt 与 file2.txt 连接后的内容 + ```console title="输出 file.txt 的全部内容" + $ cat file.txt + ``` - ```console - $ cat file1.txt file2.txt - ``` + ```console title="查看 file1.txt 与 file2.txt 连接后的内容" + $ cat file1.txt file2.txt + ``` !!! note "为什么名字叫 cat?" 当然和猫咪没有关系,cat 这里是 con**cat**enate(连接)的缩写,因为 cat 工具实际的功能是连接多个文件,然后输出。但是当只有一个文件的时候,cat 就会直接输出这个文件,所以 cat 最常见的用途就是输出单个文件。 +!!! tip "bat" + + [bat](https://github.com/sharkdp/bat) 是一个 `cat` 的替代品,输出支持语法高亮和分页。可以使用如下命令安装: + + ```console + $ sudo apt install bat + ``` + + 在 Debian/Ubuntu 下,该命令需要使用 `batcat` 调用。例如,输出 sol1.c 文件的内容(支持 C 语言语法高亮): + + ```console + $ batcat sol1.c + ``` + #### less {#less} less 和 cat 的区别在于,cat 会一次性打印全部内容到终端中并退出,而 less 一次只显示一页,且支持向前/后滚动、搜索等功能。如果要在一个大文件中(例如 man page)查找一部分内容,less 通常要比 cat 方便得多。 @@ -577,18 +634,15 @@ $ cp [OPTION] SOURCE... DIRECTORY !!! example "复制示例" - * 将 `file1.txt` 复制一份到同目录,命名为 `file2.txt` - ```console + ```console title="将 file1.txt 复制一份到同目录,命名为 file2.txt" $ cp file1.txt file2.txt ``` - * 将 `file1.txt`、`file2.txt` 文件复制到同目录下的 `file` 目录中 - ```console + ```console title="将 file1.txt、file2.txt 文件复制到同目录下的 file 目录中" $ cp file1.txt file2.txt ./file/ ``` - * 将 `dir1` 文件夹及其所有子文件复制到同目录下的 `test` 文件夹中 - ```console + ```console title="将 dir1 文件夹及其所有子文件复制到同目录下的 test 文件夹中" $ cp -r dir1 ./test/ ``` @@ -653,31 +707,25 @@ $ rm [OPTION] FILE... 常用的选项: -| 选项 | 含义 | -| ------------------------- | ---------------------------------- | -| `-f`, `--force` | 无视不存在或者没有权限的文件和参数 | -| `-r`, `-R`, `--recursive` | 递归删除目录及其子文件 | -| `-d`, `--dir` | 删除空目录 | +| 选项 | 含义 | +| ------------------------- | -------------------------------------------------------------------- | +| `-f`, `--force` | 无视不存在或者有写保护的文件,只要对包含它的文件夹本身有权限即可删除 | +| `-r`, `-R`, `--recursive` | 递归删除目录及其子文件 | +| `-d`, `--dir` | 删除空目录 | !!! example "删除示例" - * 删除 `file1.txt` 文件: - - ```console - $ rm file1.txt - ``` - - * 删除 `test` 目录及其下的所有文件: - - ```console - $ rm -r test/ - ``` + ```console title="删除 file1.txt 文件" + $ rm file1.txt + ``` - * 删除 `test1/`、`test2/`、`file1.txt` 这些文件、目录。其中,这些文件或者目录可能不存在、写保护或者没有权限读写: + ```console title="删除 test 目录及其下的所有文件" + $ rm -r test/ + ``` - ```console - $ rm -rf test1/ test2/ file1.txt - ``` + ```console title="尝试强制删除 test1/、test2/、file1.txt 文件和目录。这些文件或者目录可能不存在、有写保护或者没有权限读写" + $ rm -rf test1/ test2/ file1.txt + ``` !!! warning "注意目录拼写" @@ -703,17 +751,13 @@ $ mkdir [OPTION] DIR_NAME... !!! example "创建目录示例" - * 创建两个目录,名字分别为 `test1`、`test2`: - - ```console - $ mkdir test1 test2 - ``` - - * 创建路径 `test1/test2/test3/`: + ```console title="创建两个目录,名字分别为 test1、test2" + $ mkdir test1 test2 + ``` - ```console - $ mkdir -p test1/test2/test3/ - ``` + ```console title="创建路径 test1/test2/test3/" + $ mkdir -p test1/test2/test3/ + ``` ### 创建文件 {#touch} @@ -724,9 +768,7 @@ $ touch FILE_NAME... !!! example "创建文件示例" - 创建两个文件,名字分别为 `file1`、`file2`: - - ```console + ```console title="创建两个文件,名字分别为 file1、file2" $ touch file1 file2 ``` @@ -777,25 +819,131 @@ $ find [OPTION] PATH [EXPRESSION] | `-size +1M` | 大于 1M 的文件,`+` 代表大于这个大小,对应地,`-` 代表小于之后的大小 | | `-or` | 或运算符,代表它前后两个条件满足一个即可 | +如果不添加任何其他选项,find 会递归地输出提供的 PATH 下的所有文件。 + !!! example "搜索示例" - * 在当前目录搜索名为 report.pdf 的文件: + ```console title="在当前目录搜索名为 report.pdf 的文件" + $ find . -name 'report.pdf' + ``` + + ```console title="全盘搜索大于 1G 的文件" + $ find / -size +1G + ``` - ```console - $ find . -name 'report.pdf' - ``` + ```console title="在用户目录搜索所有名为 node_modules 的文件夹" + $ find ~/ -name 'node_modules' -type d + ``` - * 全盘搜索大于 1G 的文件: +!!! tip "对搜索到的文件批量执行命令" - ```console - $ find / -size +1G - ``` + find 的一个很有用的用法是对每一个文件都执行某个命令(例如 `md5sum`): + + ```shell + find . -type f -exec md5sum {} \; + ``` - * 在用户目录搜索所有名为 node_modules 的文件夹: + 这里,`find .` 是指对当前目录(`.`)进行 `find`,并只列出文件(`-type f`)。`-exec` 后面的内容是要执行的命令,其中 `{}` 会被替换成找到的对象(文件、目录)的路径,`\;` 表示对每个对象都执行一次给定的命令,即实际运行的是: - ```console - $ find ~/ -name 'node_modules' -type d - ``` + ```shell + md5sum file1 + md5sum file2 + md5sum file3 + ... + ``` + + 如果将 `\;` 换成 `+`,那么就是将文件名称收集起来一并交给要执行的命令,即: + + ```shell + md5sum file1 file2 file3 ... + ``` + +!!! tip "fd" + + [fd](https://github.com/sharkdp/fd) 是 find 的更现代、好用的替代。在 Ubuntu 下需要安装 `fd-find` 包,并且命令名为 **`fdfind`**(而非 `fd`)。 + + 其默认接受正则表达式(见[第九章](../Ch09/index.md))作为搜索条件,例如搜索结尾为 `.conf` 的文件: + + ```console + $ fdfind '\.conf$' /etc/ + /etc/debconf.conf + /etc/gai.conf + /etc/host.conf + (以下省略) + ``` + +### 统计文件或文件夹大小 {#du} + +`du` 命令可以统计文件和目录的大小,因为目录的大小是无法直接获取的,需要统计里面所有的文件和子目录的大小之后加和才能得到。 + +```console +$ du [OPTION] [FILE or DIRECTORY] +``` + +常用的选项: + +| 选项 | 含义 | +| ------------------------ | ---------------------------------- | +| `-h`, `--human-readable` | 以人类可读的方式显示大小 | +| `-s`, `--summarize` | 仅显示总大小 | +| `-a`, `--all` | 显示所有文件和目录的大小 | +| `--max-depth N`, `-d N` | 仅显示到指定的目录深度(N 为数字) | + +`du` 需要先递归进入子目录,处理完其中所有的项目之后,才能回到上层目录并显示上层目录的总大小。 + +!!! example "du 示例" + + ```console title="显示当前目录下所有文件和目录的大小" + $ du -h + 3.8M ./share/iana-etc + 4.0K ./share/licenses/iana-etc + 4.0K ./share/licenses/tzdata + 4.0K ./share/licenses/gcc-libs + 4.0K ./share/licenses/ncurses + 4.0K ./share/licenses/zlib + 4.0K ./share/licenses/sqlite + 20K ./share/licenses/util-linux-libs + 4.0K ./share/licenses/e2fsprogs + 12K ./share/licenses/openssl + (中间内容省略) + 9.5G . + ``` + + ```console title="显示当前目录下所有文件和目录的大小,并且仅显示一层目录" + $ du -h -d 1 + 3.0G ./share + 1.1G ./bin + 337M ./include + 4.7G ./lib + 4.0K ./local + 5.0M ./src + 473M ./lib32 + 340K ./libexec + 4.0K ./man + 9.5G . + ``` + + ```console title="显示当前目录下所有文件和目录的总大小" + $ du -sh + 9.5G . + ``` + +此外,`ncdu` 命令可以以图形化和交互式的方式显示目录的内容和大小,并可以用左右方向键浏览目录,类似 Windows 的文件资源管理器。这非常便于观察哪个目录占用了较大的磁盘空间。按 `d` 可以删除当前选中的文件或目录,按 `q` 退出。 + +```plain +ncdu 1.18 ~ Use the arrow keys to navigate, press ? for help +--- /home/example/path ------------------------------------- + 53.1 MiB [##########] /main + 45.4 MiB [######## ] Contents-riscv64.gz + 40.6 MiB [####### ] /universe + 580.0 KiB [ ] /multiverse + 44.0 KiB [ ] /restricted + 8.0 KiB [ ] InRelease + 8.0 KiB [ ] Release + 4.0 KiB [ ] Release.gpg + + Total disk usage: 139.7 MiB Apparent size: 139.6 MiB Items: 29 +``` ### 模式匹配 {#pattern} @@ -873,54 +1021,42 @@ $ tar [OPTIONS] FILE... !!! example "tar 使用实例" - * 将 `file1`、`file2`、`file3` 打包为 `target.tar`: - - ```console - $ tar -c -f target.tar file1 file2 file3 - $ # 省略 - 符号也是可以的 - $ tar cf target.tar file1 file2 file3 - ``` - - * 将 `target.tar` 中的文件提取到 `test` 目录中: - - ```console - $ tar -x -f target.tar -C test/ - $ # 或者: - $ tar xf target.tar -C test/ - ``` - - * 将 `file1`、`file2`、`file3` 打包,并使用 gzip 算法压缩,得到压缩文件 `target.tar.gz` : - - ```console - $ tar -cz -f target.tar.gz file1 file2 file3 - $ # 可以总是使用 -a 选项,避免记忆的麻烦 - $ tar caf target.tar.gz file1 file2 file3 - ``` - - * 将压缩文件 `target.tar.gz` 解压到 `test` 目录中: + ```console title="将 file1、file2、file3 打包为 target.tar" + $ tar -c -f target.tar file1 file2 file3 + $ # 省略 - 符号也是可以的 + $ tar cf target.tar file1 file2 file3 + ``` - ```console - $ tar -xz -f target.tar.gz -C test/ - $ # 或者这样: - $ tar xaf target.tar.gz -C test - ``` + ```console title="将 target.tar 中的文件提取到 test 目录中" + $ tar -x -f target.tar -C test/ + $ # 或者: + $ tar xf target.tar -C test/ + ``` - * 将 `archive1.tar`、`archive2.tar`、`archive3.tar` 三个存档文件中的文件追加到 `archive.tar` 中 + ```console title="将 file1、file2、file3 打包,并使用 gzip 算法压缩,得到压缩文件 target.tar.gz" + $ tar -cz -f target.tar.gz file1 file2 file3 + $ # 可以总是使用 -a 选项,避免记忆的麻烦 + $ tar caf target.tar.gz file1 file2 file3 + ``` - ```console - $ tar -Af archive.tar archive1.tar archive2.tar archive3.tar - ``` + ```console title="将压缩文件 target.tar.gz 解压到 test 目录中" + $ tar -xz -f target.tar.gz -C test/ + $ # 或者这样: + $ tar xaf target.tar.gz -C test + ``` - * 列出 `target.tar` 存档文件中的内容 + ```console title="将 archive1.tar、archive2.tar、archive3.tar 三个存档文件中的文件追加到 archive.tar 中" + $ tar -Af archive.tar archive1.tar archive2.tar archive3.tar + ``` - ```console - $ tar -t -f target.tar - $ tar tf target.tar + ```console title="列出 target.tar 存档文件中的内容" + $ tar -t -f target.tar + $ tar tf target.tar - $ # 打印出文件的详细信息 - $ tar -tv -f target.tar - $ tar tvf target.tar - ``` + $ # 打印出文件的详细信息 + $ tar -tv -f target.tar + $ tar tvf target.tar + ``` !!! tip "存档文件的后缀名" diff --git a/docs/Ch05/index.md b/docs/Ch05/index.md index 55896b20..65c6f4d7 100644 --- a/docs/Ch05/index.md +++ b/docs/Ch05/index.md @@ -362,6 +362,10 @@ graph LR 当然,实际情况不一定会和以下介绍的内容完全一致。可以使用 `man hier` 和 `man file-hierarchy` 查看你的系统中关于文件系统层次结构的文档。 +??? note "Systemd 的文件系统层次结构" + + 如果你阅读了 `man hier` 和 `man file-hierarchy`,你会发现它们之间有一些差异。例如后者有 `/efi` 目录,前者未提及。这是因为后者是 Systemd 使用的文件系统层次结构,在 FHS 的基础上做了一些扩展。但是总体来说,两者是类似的。 + `/bin` : 存储必须的程序文件,对所有用户都可用。 @@ -455,95 +459,6 @@ graph LR - `/var/run`:存储程序运行时的数据(部分发行版会将该目录符号链接到 `/run` 目录)。 - `/var/spool`:存储「等待进一步处理」的程序数据。 -## 列出文件系统项目 {#list-objects} - -经常我们需要在 Shell 中列出某个目录下的项目(子目录和文件)。`ls` 命令是最常见的用来列出文件系统项目的命令,`ls -la` 则可以显示隐藏文件(`-a`)和更详细的信息(`-l`)。但是,`ls` 只能显示某个目录下的文件和子目录,并不会深入子目录内部继续检查。下面介绍几个命令,常用于获取这些信息。 - -### `find` 命令 {#cmd-find} - -`find` 命令可以列出某个目录下所有的目录和文件,并**递归地**进入子目录。基本用法是 - -```shell -$ find /etc -/etc -/etc/analog.cfg -/etc/hosts.deny -/etc/initramfs-tools -/etc/initramfs-tools/initramfs.conf -/etc/initramfs-tools/hooks -/etc/initramfs-tools/conf.d -/etc/initramfs-tools/conf.d/resume -/etc/initramfs-tools/modules -/etc/initramfs-tools/update-initramfs.conf -... (省略) -``` - -可以看到,`find` 命令将列出指定的目录下的文件和子目录名称,在遇到子目录时立即进入目录并递归地执行上面的操作。 - -该命令的一个很有用的用法是对每一个文件都执行某个命令(例如 `md5sum`): - -```shell -find . -type f -exec md5sum {} \; -``` - -这里,`find .` 是指对当前目录(`.`)进行 `find`,并只列出文件(`-type f`)。`-exec` 后面的内容是要执行的命令,其中 `{}` 会被替换成找到的对象(文件、目录)的路径,`\;` 表示对每个对象都执行一次给定的命令,即实际运行的是 - -```shell -md5sum file1 -md5sum file2 -md5sum file3 -... -``` - -如果将 `\;` 换成 `+`,那么就是将文件名称收集起来一并交给要执行的命令,即 - -```shell -md5sum file1 file2 file3 ... -``` - -### `du` 命令 {#cmd-du} - -`du` 命令可以统计文件和目录的大小。目录的大小是无法直接获取的,需要统计里面所有的文件和子目录的大小之后加和才能得到。`du` 命令的输出类似这样: - -```shell -$ du -h /etc/ -4.0K /etc/initramfs-tools/hooks -8.0K /etc/initramfs-tools/conf.d -4.0K /etc/initramfs-tools/scripts/local-premount -4.0K /etc/initramfs-tools/scripts/nfs-premount -... (省略) -4.0K /etc/initramfs-tools/scripts/panic -4.0K /etc/initramfs-tools/scripts/local-top -44K /etc/initramfs-tools/scripts -72K /etc/initramfs-tools -12K /etc/udisks2 -16K /etc/fonts/conf.d -60K /etc/fonts/conf.avail -84K /etc/fonts -``` - -由于前面说到的原因,`du` 需要先递归进入子目录,处理完其中所有的项目之后,才能回到上层目录并显示上层目录的总大小。类似 `ls -h`,这里的 `-h` 表示以人类可读的方式进行显示,`-b` 则可以显示字节数,`-a` 可以使得输出包含文件的大小(默认只显示各层级目录的大小)。 - -### `ncdu` 命令 {#cmd-ncdu} - -`ncdu` 命令可以以图形化和交互式的方式显示目录的内容和大小,并可以用左右方向键浏览目录,类似 Windows 的文件资源管理器。这非常便于观察哪个目录占用了较大的磁盘空间。 - -```plain -ncdu 1.18 ~ Use the arrow keys to navigate, press ? for help ---- /home/xxxxxx(略去) ----------------- - /.. - 53.1 MiB [##########] /main - 45.4 MiB [######## ] Contents-riscv64.gz - 40.6 MiB [####### ] /universe - 580.0 KiB [ ] /multiverse - 44.0 KiB [ ] /restricted - 8.0 KiB [ ] InRelease - 8.0 KiB [ ] Release - 4.0 KiB [ ] Release.gpg - - Total disk usage: 139.7 MiB Apparent size: 139.6 MiB Items: 29 -``` - ## 思考题 {#questions} !!! question "nobody 用户" diff --git a/docs/Ch06/index.md b/docs/Ch06/index.md index 05721c95..24c5b504 100644 --- a/docs/Ch06/index.md +++ b/docs/Ch06/index.md @@ -279,6 +279,23 @@ $ grep -R 'hello' . # 递归查找当前目录下内容包含 hello 的文件 grep 事实上是非常强大的查找工具,[第九章](../Ch09/index.md)将在介绍正则表达式语法之后进一步介绍 grep。 +!!! tip "ripgrep" + + 除了 grep 以外,还有一个更快更强大的工具 [ripgrep](https://github.com/BurntSushi/ripgrep)。其会默认递归查找当前目录下的文件。安装 `ripgrep` 包后使用 `rg` 命令,即可作为 `grep -R` 的替代: + + ```console + $ # 在 /etc/ 下搜索包含 localhost 的文件 + $ rg localhost /etc/ + /etc/hosts + 1:127.0.0.1 localhost + 2:::1 localhost + + /etc/security/pam_env.conf + 52:# to "localhost" rather than not being set at all + 53:#REMOTEHOST DEFAULT=localhost OVERRIDE=@{PAM_RHOST} + 64:#NNTPSERVER DEFAULT=localhost + ``` + ### 文本替换:sed {#sed} `sed` 命令可以替换文本中的字符串: