Linux上查找和放置系统文件

时间:2021-06-19 08:40:11

概述

在篇中,学习文件系统层级标准 (FHS)。学习:

  • 确定将文件放在 FHS 下的位置
  • 查找 Linux 系统上的文件和命令
  • 查找 FHS 中定义的其他重要文件和目录,并理解它们的用途

文件系统层级标准

通过在所有 Linux 发行版中都将文件放在同一个一般位置,FHS 简化了与发行版独立的软件开发。FHS 还可以用在 Linux Standard Base 中(参见参考资料)。FHS 允许用户和软件预测安装的文件和目录的位置。符合 FHS 的文件系统假设操作系统支持大多数 UNIX 文件系统中包含的基本安全功能。

两个独立的 FHS 类别

FHS 的核心是两种独立的文件特征:

可共享和不可共享
可共享文件可放在一个系统上并在另一个系统上使用,而不可共享文件必须位于使用它们的系统上。
静态和可变
静态文件仅通过系统管理员干预进行更改,比如安装或升级一个包,它们包括文档、库和二进制文件。可变文件是其他所有文件,比如日志、假脱机文件、数据库和用户数据,它们可由用户和系统进程更改。

这些不同之处使得具有不同的特征集的文件可以存储在不同的文件系统上。表 1是一个来自 FHS 文档的示例,展示了一种符合 FHS 的布局。

表 1. FHS 示例
  可共享 不可共享
静态 /usr
/opt
/etc
/boot
可变 /var/mail
/var/spool/news
/var/run
/var/lock

Linux 系统通常包含数十万个文件。我最近安装的一个 64 位 Fedora 22 系统仅在 /usr 分层结构中就有 170,000 多个文件。

 [root@atticf22 ~]# find /usr -type f | wc -l
 174182

我的其他大部分安装都拥有超过 100,000 个文件,通常拥有 200,000 个或更多的文件。接下来的几节将介绍帮助您在如此浩瀚的数据海洋中查找文件(特别是程序)的工具。

您的可执行文件的路径

如果您使用过多个 Linux 系统,您可能已经注意到,在您以 root 身份进行登录时,能够执行一些作为普通用户无法执行的命令。一些命令可由用户执行,但不能由 root 执行。当您在命令行上运行程序时,bash(或其他)shell 会在一个目录列表中搜索,以找到您请求的程序。该目录列表在 PATH 环境变量中指定。在旧版的系统上,root 用户的路径通常包含 /sbin,而非 root 用户的路径不包含它。清单 1展示了来自 3 个不同发行版的用户和 root 路径示例。

清单 1. 一些 PATH 示例
 [ian@attic4-cent ~]$ # CentOS 6
 [ian@attic4-cent ~]$ echo $PATH
 /usr/lib64/qt-3.3/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin:/home/ian/bin 
 [ian@attic4-cent ~]$ su -
 Password: 
 [root@attic4-cent ~]# echo $PATH
 /usr/lib64/qt-3.3/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin 

 [ian@atticf22 ~]$ # echo Fedora 22
 [ian@atticf22 ~]$ echo $PATH
 /usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:/home/ian/.local/bin:/home/ian/bin 
 [ian@atticf22 ~]$ su -
 Password: 
 [root@atticf22 ~]# echo $PATH
 /usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin 
 [root@atticf22 ~]# ls -l /sbin
 lrwxrwxrwx. 1 root root 8 Aug 16  2014 /sbin -> usr/sbin 

 ian@attic-mint17 ~ $ # Linux Mint 17.2
 ian@attic-mint17 ~ $ echo $PATH
 /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games 
 ian@attic-mint17 ~ $ sudo -s
 attic-mint17 ~ # echo $PATH
 /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin 
 attic-mint17 ~ # fortune
 Command 'fortune' is available in '/usr/games/fortune'
 The command could not be located because '/usr/games' is not included in the PATH environment variable. 
 fortune: command not found

您可以看到,PATH 变量只是一组以冒号分隔的目录名称。请注意 CentOS 的用户路径和 root 路径之间的区别,以及 Linux Mint 用户路径中的两个额外的游戏目录。因为fortune 游戏命令实际位于 /usr/games/fortune 中,所以 Mint root 用户无法玩游戏,除非他或她提供了完全限定的路径名。在用户路径中不包含 /sbin 目录的系统上,tune2fs 等程序通常只能由 root 用户找到。

通常,您的路径在一个初始化文件中设置,比如 .bash_profile 或 .bashrc。您可以通过指定新路径,针对当前 bash 进程来更改它。如果您希望新值可用于您从这个进程启动的其他进程,请记住导出 PATH 变量。假设我正在 test-hello 目录中开发一个 “Hello World” 应用程序。清单 2展示了如何将它添加到我的路径并运行我的 hello 可执行文件,而不需要每次都提供一个完全限定路径。

清单 2. 更改您的路径
 [ian@atticf22 ~]$ hello
 bash: hello: command not found... 
 [ian@atticf22 ~]$ test-hello/hello
 Hello World! 
 [ian@atticf22 ~]$ export PATH=~/test-hello:$PATH
 [ian@atticf22 ~]$ hello
 Hello World!

which、type 和 whereis 命令

which 命令

可以使用 which 命令搜索您的路径,找到在您键入一个命令时将执行哪个命令(如果有)。清单 3给出了一个在我们更新该路径之前和之后查找hello 命令的示例。

清单 3. 使用 which
 [ian@atticf22 ~]$ echo $PATH
 /usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin:/home/ian/.local/bin:/home/ian/bin 
 [ian@atticf22 ~]$ which hello
 /usr/bin/which: no hello in (/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin: 
 /home/ian/.local/bin:/home/ian/bin) 
 [ian@atticf22 ~]$ export PATH=~/test-hello:$PATH
 [ian@atticf22 ~]$ echo $PATH
 /home/ian/test-hello:/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin: 
 /home/ian/.local/bin:/home/ian/bin 
 [ian@atticf22 ~]$ which hello
 ~/test-hello/hello

which 命令显示了一个命令在您的路径中第一次出现的位置。如果您想知道该命令是否出现了多次,可以添加 -a 选项,如 清单 4所示。

清单 4. 使用 which 查找多个出现位置
 [ian@atticf22 ~]$ which awk
 /usr/bin/awk 
 [ian@atticf22 ~]$ which -a awk
 /usr/bin/awk 
 /bin/awk

在这里,我们在两个地方找到了 awk 命令:在 /usr/bin 中(这是系统上的命令的主要目录)和在 /bin 中(它包含系统管理员和用户都可使用,但在未挂载其他文件系统时需要的命令)。

清单 5. awk 命令非常容易使用
 [ian@atticf22 ~]$ ls -l $(which -a awk)
 lrwxrwxrwx. 1 root root 4 Jan  2  2015 /bin/awk -> gawk 
 lrwxrwxrwx. 1 root root 4 Jan  2  2015 /usr/bin/awk -> gawk 
 [ian@atticf22 ~]$ ls -ld /bin /usr/bin
 lrwxrwxrwx. 1 root root     7 Aug 16  2014 /bin -> usr/bin 
 dr-xr-xr-x. 2 root root 69632 Aug 10 10:40 /usr/bin

在这个 Fedora 22 系统上,/bin 实际上是 /usr/bin 的符号链接,您可能感到很奇怪。

type 类型

有一些命令 which命令无法找到,比如 shell 内建命令。type 命令是一个内建命令,它告诉您如何评估一个给定命令字符串的执行情况。清单 6使用了whichtype 来表明 type 命令不是您的路径中的可执行文件,而是一个 shell 内建命令。

清单 6. 使用 type
 [ian@atticf22 ~]$ which type
 /usr/bin/which: no type in (/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin: 
 /home/ian/.local/bin:/home/ian/bin) 
 [ian@atticf22 ~]$ type type
 type is a shell builtin

whereis 命令

如果您想了解比程序的位置更多的信息,可以使用 whereis命令。例如,您可以查找手册页或其他信息,如 清单 7所示。

清单 7. 使用 whereis 查找手册页
 [ian@atticf22 ~]$ whereis awk
 awk: /usr/bin/awk /usr/libexec/awk /usr/share/awk /usr/share/man/man1p/awk.1p.gz 
 /usr/share/man/man1/awk.1.gz

请注意,/bin 中的 awk 部分没有被 whereis 找到。whereis 使用的目录是固定的,所以该命令并不总是能找到您寻找的命令。whereis 命令也可以搜索源文件,指定替代搜索路径,并搜索不常见的条目。请参阅手册页,了解如何覆盖此行为或者更改whereis所使用的固定路径。

find 命令

find 命令就像是 Linux 系统上的文件搜索工具的瑞士军刀。您可能发现有用的另外两个功能是:它可以基于用户或组名称来查找文件,或者基于权限来查找文件。

假设您想看看一个用户在 /tmp 分层结构中有哪些文件。清单 8展示了 root 用户如何查找用户 ian 在 /tmp 中的所有文件。

清单 8. 按用户和组查找文件
 [root@atticf22 ~]# find /tmp -user ian 
 /tmp/jna-104022 
 ... 
 /tmp/hsperfdata_ian 
 /tmp/hsperfdata_ian/2390 
 /tmp/tracker-extract-files.1000 
 /tmp/.esd-1000 
 /tmp/.esd-1000/socket 
 /tmp/.X11-unix/X0 
 /tmp/.ICE-unix/1668

您还可以使用 -group 测试来按组查找文件。您可以使用 -nouser-nogroup 选项找到不属于系统上的任何用户或组的文件。与其他测试一样,您可以使用! 对该测试求反。我通常将我的用户编号设置为 1000,因为这是许多系统上的默认设置。我还创建了一个名为 ian,组编号为 1000 的组,以防系统没有自动创建它。其他系统仍从 500 开始,或者默认情况下将新用户放在组 “users” 中。我的一些从 Red Hat 6.2 系统存档的旧研究材料仍拥有用户 500。

清单 9展示了如何查找一些不归我当前的用户组所有的目录。research/rh62/involution 归用户 500 和组 4 所有,二者都不存在于我的当前系统上。要按数字用户 id 或组 id 查找文件或目录,可以使用-uid-gid 进行测试。

清单 9. 查找不归 ian 所有的目录
 [ian@atticf22 ~]$ find -L research -maxdepth 2 -type d ! -group ian
 research/rh62/involution 
 research/rh62/programs 
 research/lost+found 
 find: ‘ research/lost+found ’ : Permission denied 
 [ian@atticf22 ~]$ ls -ld research/rh62/involution
 drwxr-xr-x. 2 500 adm 4096 Nov 10  1999 research/rh62/involution

要按权限查找文件,可以使用 -perm测试和类似 chmodumask 命令所使用的符号表达式。您可以搜索准确的权限,但更有用的做法通常是在权限表达式前添加一个连字符作为前缀,以表明您想要设置了这些权限的文件,但并不关心其他权限。清单 10演示了如何查找用户、组和每个人可执行的文件,以及查找其他用户无法读取的文件的两种不同方式。

清单 10. 按权限查找文件
 [ian@atticf22 ~]$ find . -maxdepth 1 -type f -perm -uga=x
 ./hello 
 [ian@atticf22 ~]$ find . -maxdepth 1 ! -perm  -o=r
 . 
 ./.ssh 
 ./.ICEauthority 
 ./.bash_history 
 ./.config 
 ... 
 ./.kde 
 ./.cache 
 [ian@atticf22 ~]$ find . -maxdepth 1 ! -perm  -0004
 . 
 ./.ssh 
 ./.ICEauthority 
 ./.bash_history 
 ./.config 
 ... 
 ./.kde 
 ./.cache

我们介绍了您可以使用 find命令执行的一些主要的搜索类型。为了进一步缩小输出范围,您可以组合多个表达式,可以向组合中添加正则表达式。要进一步了解这个多功能的命令,可以使用手册页,在您安装了信息系统时,最好使用info find

清单 11展示了最后一个使用 find 搜索的示例。这个示例使用 cd 转到 /usr/include,以便可以管理清单长度,然后找到所有在其路径名中包含packet(无论大小写)的文件。第二个示例将此输出进一步限制到不是目录而且至少有 1500 字节的文件。根据您安装了哪些包,您系统上的实际输出可能有所不同。

清单 11. find 的最后一个示例
 [ian@atticf22 ~]$ cd /usr/include
 [ian@atticf22 include]$ find . -iregex ".*packet.*"
 ./net/if_packet.h 
 ./linux/packet_diag.h 
 ./linux/if_packet.h 
 ./netpacket 
 ./netpacket/packet.h 
 [ian@atticf22 include]$ find . -iregex ".*packet.*" ! -type d -size +1500c
 ./linux/packet_diag.h 
 ./linux/if_packet.h 
 ./netpacket/packet.h

请注意,该正则表达式必须与 find 返回的完整路径相匹配,而且请记住正则表达式与通配符之间的区别。

locate 和 updatedb 命令

在每次运行 find 命令时,该命令都会搜索您指定的所有目录。要加快运行速度,可以使用另一个命令 locate,它使用已存储路径信息的数据库,而不是每次都搜索文件系统。

locate 命令

locate 命令搜索通常由一个计划作业每天更新的数据库中的匹配文件。

locate 命令与路径名的任何部分匹配,而不只是与文件名匹配。将文件名放在单引号中,包含至少一个通配符来更准确地匹配。清单 12展示了如何查找包含字符串bin/ls 的路径,还展示了两个使用通配符来限制输出的示例。

清单 12. 使用 locate 查找路径和限制输出
 [ian@attic4-cent ~]$ # CentOS 6
 [ian@attic4-cent ~]$ locate /bin/ls
 /bin/ls 
 /bin/lsblk 
 /bin/lscgroup 
 /bin/lssubsys 
 /usr/bin/lsattr 
 /usr/bin/lsb_release 
 /usr/bin/lscpu 
 /usr/bin/lsdiff 
 /usr/bin/lshal 
 /usr/bin/lslogins 
 /usr/bin/lsusb 
 /usr/bin/lsusb.py 
 [ian@attic4-cent ~]$ locate '\/bin/ls'
 /bin/ls 
 [ian@attic4-cent ~]$ locate '/bin/ls*'
 /bin/ls 
 /bin/lsblk 
 /bin/lscgroup 
 /bin/lssubsys

updatedb 命令

locate 使用的默认数据库存储在 /var 文件系统中的一个位置中,比如 /var/lib/locatedb。这个位置在使用 slocate 或 mlocate 包来提供额外的安全性或更高速度的系统上可能不同。您可以使用locate -S 查找您的 locate 数据库上的统计数据,如 清单 13所示。

清单 13. Locatedb 统计数据
 [ian@attic4-cent ~]$ # CentOS 6
 [ian@attic4-cent ~]$ locate -S
 Database /var/lib/mlocate/mlocate.db: 
	 77,143 directories 
	 776,460 files 
	 56,872,710 bytes in file names 
	 21,074,461 bytes used to store database

使用 updatedb 命令创建或更新该数据库。该命令通常作为计划作业每天运行。文件 /etc/updatedb.conf(或者有时候是 /etc/sysconfig/locate)是updatedb 的配置文件。要启用每日更新,root 用户需要编辑 /etc/updatedb.conf 并设置 DAILY_UPDATE=yes。要立即创建该数据库,可以 root 身份运行updatedb 命令。

使用 locate 的其他考虑因素包括 updatedb 数据库的每日构建的安全考虑因素和网络文件 I/O 考虑因素。请查阅手册页和updatedb 配置文件来了解更多的细节。

root 文件系统中的 FHS 目录

FHS 目标是保持 root 文件系统尽可能小。但是,它必须包含引导、还原、恢复或修复系统所需的所有文件,包括经验丰富的管理员需要用于执行这些任务的实用程序。请注意,引导一个系统要求 root 文件系统上有足够的文件来允许挂载其他系统。

表 2展示了 FHS 需要的 root(或 /)文件系统中的目录的用途。目录或它的符号链接必须存在一个,除非它们被标记为可选(此时仅在存在相应的子系统时才需要它们)。

表 2. FHS root 文件系统
与运行进程相关的数据
目录 用途
bin 基本的命令二进制文件
boot 引导加载程序的静态文件
dev 设备文件
etc 特定于主机的系统配置
lib 基本的共享库和内核模块
media 可移动设备的挂载点
mnt 临时挂载文件系统的挂载点
opt 附加应用软件包
run  
sbin 基本的系统二进制文件
srv 此系统提供的服务的数据
tmp 临时文件
usr 辅助分层结构
var 变量数据
home 用户主目录(可选)
lib<qual> 替代性格式基本共享库(可选)
root root 用户的主目录(可选)

/usr 和 /var 分层结构

/usr 和 /var 分层结构非常复杂,以至于 FHS 中有几个专门介绍它们的小节。/usr 文件系统是文件系统的第二个主要部分,包含可共享、只读的数据。它可以在系统之间共享,但目前的做法常常未这么做。

/var 文件系统包含变量数据文件,包括假脱机目录和文件、管理和日志数据,以及瞬时和临时文件。/var 的一些部分无法在不同的系统之间共享,但其他文件可以共享,比如 /var/mail、/var/cache/man、/var/cache/fonts 和 /var/spool/news。

备注:3.0 版 FHS 将 /var/run 分层结构转移到了一个单独的 /run 分层结构。/run 目录包含自系统引导以来描述它的系统信息。此目录下的文件必须在引导时删除或删节。程序可以继续使用 /var/run 实现向后兼容性,但应转而使用 /run。

要全面理解该标准,请查阅 FHS 文档(参见 参考资料)。

对 Linux 上的文件放置的介绍到此结束。