Linux工作原理13用户环境

13用户环境

本书主要关注 Linux 系统中通常作为服务器进程和交互式用户会话基础的部分。但是,系统和用户最终还是要在某个地方相遇。在这一点上,启动文件扮演着重要角色,因为它们为 shell 和其他交互式程序设置了默认值。它们决定了用户登录时系统的行为方式。

大多数用户不会密切关注他们的启动文件,只有当他们想添加一些方便的东西(如别名)时才会触碰它们。久而久之,这些文件就会被不必要的环境变量和测试搞得杂乱无章,从而导致恼人(或相当严重)的问题。

如果你的 Linux 机器已经使用了一段时间,你可能已经注意到你的主目录随着时间的推移积累了大量令人费解的启动文件。这些文件有时也被称为点文件,因为它们几乎总是以点(.)开头,因此被排除在 ls 和大多数文件管理器的默认显示之外。其中许多文件会在首次运行程序时自动创建,你永远不需要更改它们。本章主要介绍 shell 启动文件,因为它们是你最有可能修改或从头开始重写的文件。让我们先来看看在处理这些文件时需要注意的事项。

13.1 创建启动文件的指导原则

在设计启动文件时,要牢记用户。如果你是机器上的唯一用户,你就不用太担心,因为任何错误都只会影响到你,而且很容易修复。但是,如果你创建的启动文件是一台机器或网络上所有新用户的默认设置,或者你认为有人可能会将你的文件复制到另一台机器上使用,那么这个过程就变得相当重要了。如果你在启动文件中犯了一个错误,并将其分发给 10 个用户,那么你最终可能要修复这个错误 10 次。

在为其他用户创建启动文件时,请牢记两个基本目标:

简洁 启动文件的数量要少,文件要尽量简短,这样既容易修改,又不易破坏。启动文件中的每一个项目都有可能被破坏。
可读性 在文件中使用大量注释,以便用户清楚地了解文件中每个部分的作用。

13.2 何时修改启动文件

在修改启动文件之前,先问问自己是否真的应该修改。以下是更改启动文件的一些好理由:

  • 想更改默认提示。
  • 需要容纳某些关键的本地安装软件。(不过可以先考虑使用封装脚本)。
  • 你现有的启动文件已损坏。
  • 如果你的 Linux 发行版中的所有文件都能正常运行,那就要小心了。有时,默认启动文件会与 /etc 中的其他文件发生交互。

不过,如果你对更改默认值不感兴趣,你可能就不会阅读本章了,所以让我们来看看哪些是重要的。

13.3 shell 启动文件元素

shell 启动文件包含哪些内容?有些内容似乎显而易见,例如命令路径和提示设置。但路径中到底应该包含哪些内容,合理的提示符应该是什么样的?启动文件中应该包含多少内容?

本节将讨论 shell 启动文件的基本要素--从命令路径、提示符、别名到权限掩码。

13.3.1 命令路径

shell 启动文件中最重要的部分是命令路径。该路径应涵盖包含普通用户感兴趣的所有应用程序的目录。至少,路径应按顺序包含以下内容:

/usr/local/bin
/usr/bin
/bin

这样的顺序可确保你能用位于 /usr/local 目录中的特定站点变量覆盖标准默认程序。

大多数 Linux 发行版都会将几乎所有打包用户软件的可执行文件安装在 /usr/bin 中。有些是多年来偶尔出现的差异,比如把游戏放在 /usr/games,把图形应用程序放在单独的位置,所以请先检查你的系统默认设置。确保系统中的每个通用程序都可以通过刚才列出的目录之一使用。否则,你的系统很可能会失控。不要为了适应每一个新的软件安装目录而改变用户环境的默认路径。在 /usr/local/bin 中使用符号链接是适应独立安装目录的一种经济方法。

许多用户都会创建一个自己的 bin 目录来存储 shell 脚本和程序,因此你可能需要在路径前面添加这个目录:

$HOME/bin

注意:新的惯例是将二进制文件放在 $HOME/.local/bin。

如果你对系统实用程序(如 sysctl、fdisk 和 lsmod)感兴趣,请在路径中添加 sbin 目录:

/usr/local/sbin
/usr/sbin
/sbin

有一个小的但有争议的命令路径组件需要讨论:点。在路径中加点(.)可以让你在当前目录下运行程序,而无需在程序名称前使用 ./。这在编写脚本或编译程序时似乎很方便,但由于以下两个原因,这不是个好主意:

  • 它会带来安全问题。绝对不能在路径前面加点。举个可能发生的例子,攻击者可以在互联网上发布的归档文件中植入名为 ls 的木马。即使把点放在路径的末尾,你仍然很容易被攻击者预料到诸如 sl 或 ks 这样的错别字。
  • 不一致,容易混淆。路径中的点可能意味着命令的行为会根据当前目录发生变化。

13.3.2 手动页面路径

传统的手动页面路径由 MANPATH 环境变量决定,但不应设置它,因为这样做会覆盖 /etc/manpath.config 中的系统默认值。

13.3.3 提示

有经验的用户往往会避免冗长、复杂、无用的提示。相比之下,许多管理员和发行版会把所有东西都拖进默认提示中。甚至许多 shell 的默认提示符也是杂乱无章或毫无用处的。例如,默认的 bash 提示包含 shell 名称和版本号。你的选择应该反映用户的需求;如果真的有帮助,可以在提示符中加入当前工作目录、主机名和用户名。

最重要的是,要避免使用对 shell 有重要意义的字符,例如这些字符:

{ } = & < >

要特别注意避免使用 > 字符,因为如果你不小心复制粘贴了 shell 窗口的某一部分,它可能会导致当前目录中出现不稳定的空文件(> 会将输出重定向到文件)。

这个简单的 bash 提示符设置以习惯的 $ 结尾(传统的 csh 提示符以 % 结尾):

PS1='\u\$ '
  • \u 是 shell 对当前用户名求值的表达式(参见 bash(1) 手册中的 PROMPTING 部分)。其他常用表达式包括
  • \h 主机名(简写,不含域名)。
  • ! 历史记录编号。
  • \w 当前目录。因为这可能会变得很长,你可以用 \W 代替,将显示限制在最后一个组件。
  • $ $ 如果以用户账户运行; # 如果以 root 用户账户运行。

13.3.4 别名

别名是 shell 的一项功能,它可以在执行命令前用一个字符串替换另一个字符串。别名是一种高效的快捷方式,可以节省输入次数。不过,别名也有几个缺点:

  • 操作参数可能比较麻烦。
  • 它们容易混淆;shell 的内置 which 命令可以告诉你某个东西是否是别名,但不会告诉你它是在哪里定义的。
  • 在子shell和非交互式shell中,别名是不受欢迎的;它们不会传递给子shell。
  • 定义别名时的一个典型错误是为已有命令添加额外参数,例如将 ls 别名为 ls -F。往好了说,这会导致在不需要时很难移除 -F 参数。最糟糕的情况是,如果用户不明白他们使用的不是默认参数,就会造成严重后果。

鉴于这些缺点,你应该尽可能避免使用别名;编写 shell 函数或全新的 shell 脚本会更容易。计算机启动和执行 shell 的速度非常快,别名和全新命令之间的差别应该不会被注意到。

不过,当你想改变 shell 环境的某个部分时,别名确实会派上用场。你不能用 shell 脚本改变环境变量,因为脚本是作为子shell 运行的。(但你可以定义 shell 函数来完成这项任务)。

13.3.5 权限掩码

正如第 2 章所述,shell 内置的 umask(权限掩码)工具可以设置默认权限。在启动文件中加入 umask 命令,可以确保运行的程序创建的文件具有所需的权限。有两种合理的选择:

  • 077 该掩码是限制最严格的权限掩码;它不允许任何其他用户访问新文件和目录。这通常适用于多用户系统,因为你不想让其他用户查看你的任何文件。但是,如果将此掩码设置为默认值,当用户想共享文件但不了解如何正确设置权限时,有时就会出现问题。(没有经验的用户往往会将文件设置为世界可写模式)。
  • 022 该掩码允许其他用户读取新文件和目录。在单用户系统中,这可能是一个不错的选择,因为许多以伪用户身份运行的守护进程无法查看使用限制性更强的 077 umask 创建的文件和目录。

某些应用程序(尤其是邮件程序)会覆盖 umask,将其更改为 077,因为它们认为自己的文件只属于文件所有者,与其他人无关。

13.4 启动文件顺序和示例

既然你已经知道了 shell 启动文件的内容,那么是时候看看一些具体的例子了。令人惊奇的是,创建启动文件最困难和最令人困惑的部分之一就是确定使用哪一种可能的启动文件。本节将介绍两种最常用的 Unix shell:bash 和 tcsh。

13.4.1 bash shell

在 bash 中,您可以从 .bash_profile、.profile、.bash_login 和 .bashrc 这几个启动文件名中进行选择。哪个文件适合你的命令路径、手册页面路径、提示符、别名和权限掩码?答案是,你应该有一个 .bashrc 文件和一个指向 .bashrc 的 .bash_profile 符号链接,因为 bash shell 实例类型有几种。

两种主要的 shell 实例类型是交互式和非交互式,但我们只对交互式 shell 感兴趣,因为非交互式 shell(如运行 shell 脚本的 shell)通常不读取任何启动文件。交互式 shell 是用来从终端运行命令的 shell,比如你在本书中看到的那些,它们可以分为登录 shell 和非登录 shell。

  • 登录 shell

传统上,登录 shell 是指使用 /bin/login 等程序通过终端登录系统时获得的 shell。使用 SSH 远程登录时也会得到一个登录 shell。基本原理是,登录 shell 是一个初始 shell。你可以通过运行 echo $0 来判断一个 shell 是否是登录 shell;如果第一个字符是“-”,那么这个 shell 就是登录 shell。

当 bash 作为登录 shell 运行时,它会运行 /etc/profile。然后,它会查找用户的 .bash_profile、.bash_login 和 .profile 文件,只运行看到的第一个文件。

虽然听起来很奇怪,但还是可以把一个非交互式 shell 作为登录 shell 运行,以强制它运行启动文件。为此,请使用 -l 或 --login 选项启动 shell。

  • 非登录 shell

非登录 shell 是登录后运行的附加 shell。简单地说,它是任何非登录 shell 的交互式 shell。除非你特别要求使用登录 shell,否则窗口系统终端程序(xterm、GNOME 终端等)会启动非登录 shell。

以非登录 shell 启动时,bash 会运行 /etc/bash.bashrc,然后运行用户的 .bashrc。

  • 两种 shell 的原因
    两种不同启动文件背后的原因是,在过去,用户通过传统终端登录 shell,然后使用窗口系统或屏幕程序启动非登录子壳。对于非登录子壳,重复设置用户环境和运行一堆已经运行过的程序被认为是一种浪费。有了登录 shell,你就可以在 .bash_profile 这样的文件中运行花哨的启动命令,只需在 .bashrc 中留下别名和其他 “轻量级 ”命令即可。

现在,大多数桌面用户都通过图形显示管理器登录(下一章将详细介绍)。为了保持登录与非登录的模式,这些程序大多从一个非交互式登录 shell 开始。如果不这样做,你就需要在 .bashrc 中设置整个环境(路径、手动路径等),否则你将永远无法在终端窗口中看到任何环境。不过,如果你想在控制台或远程登录,你也需要一个 .bash_profile 文件,因为这些登录shell根本不需要 .bashrc。

  • .bashrc 示例
    为了同时满足非登录 shell 和登录 shell 的需要,你该如何创建一个 .bashrc 文件,并将其用作 .bash_profile 呢?下面是一个非常简单(但完全足够)的例子:
# Command path.
PATH=/usr/local/bin:/usr/bin:/bin:/usr/games
PATH=$HOME/bin:$PATH

# PS1 is the regular prompt. 
# Substitutions include:
# \u username \h hostname \w current directory
# \! history number \s shell name \$ $ if regular user
PS1='\u\$ '

# EDITOR and VISUAL determine the editor that programs such as less
# and mail clients invoke when asked to edit a file.
EDITOR=vi
VISUAL=vi

# PAGER is the default text file viewer for programs such as man.
PAGER=less

# These are some handy options for less.
# A different style is LESS=FRX
# (F=quit at end, R=show raw characters, X=don't use alt screen)
LESS=meiX

# You must export environment variables.
export PATH EDITOR VISUAL PAGER LESS

# By default, give other users read-only access to most new files.
umask 022

在这个启动文件中,路径前面是 $HOME/bin,这样那里的可执行文件就优先于系统版本。如果需要系统可执行文件,则添加 /sbin 和 /usr/sbin。

如前所述,你可以通过符号链接与 .bash_profile 共享 .bashrc 文件,也可以通过创建 .bash_profile 这样的单行文件,使两者之间的关系更加清晰:

. $HOME/.bashrc
  • 检查登录和交互式 shell

如果 .bashrc 与 .bash_profile 相匹配,通常就不会为登录 shell 运行额外的命令。不过,如果您想为登录 shell 和非登录 shell 定义不同的操作,可以在 .bashrc 中添加以下测试,检查 shell 的 $- 变量中是否有 i 字符:

case $- in
 *i*) # interactive commands go here
    command
    --snip--
    ;;
 *)   # non-interactive commands go here
    command
    --snip--
    ;;
esac

参考资料

13.4.2 tcsh shell

几乎所有 Linux 系统上的标准 csh 都是 tcsh,它是一种增强的 C shell,普及了命令行编辑、多模式文件名和命令补全等功能。即使你不使用 tcsh 作为默认的新用户 shell(默认应该使用 bash),你也应该提供 tcsh 启动文件,以防你的用户碰巧遇到 tcsh。

在 tcsh 中,你不必担心登录 shell 和非登录 shell 之间的区别。启动时,tcsh 会查找 .tcshrc 文件。如果找不到,它就会查找 csh shell 的 .cshrc 启动文件。这样做的原因是,你可以使用 .tcshrc 文件来处理 csh 中无法使用的 tcsh 扩展。你也许应该坚持使用传统的 .cshrc 而不是 .tcshrc;在 csh 中使用你的启动文件的可能性很小。如果用户真的在其他系统中使用 csh,你的 .cshrc 也能正常工作。

.cshrc 示例
下面是一个 .cshrc 文件示例:

# Command path.
setenv PATH $HOME/bin:/usr/local/bin:/usr/bin:/bin

# EDITOR and VISUAL determine the editor that programs such as less
# and mail clients invoke when asked to edit a file.
setenv EDITOR vi
setenv VISUAL vi

# PAGER is the default text file viewer for programs such as man.
setenv PAGER less

# These are some handy options for less.
setenv LESS meiX

# By default, give other users read-only access to most new files.
umask 022

# Customize the prompt.
# Substitutions include:
# %n username %m hostname %/ current directory
# %h history number %l current terminal %% %
set prompt="%m%% "

13.5 默认用户设置

为新用户编写启动文件和选择默认设置的最佳方法是在系统中试验一个新的测试用户。为测试用户创建一个空的主目录,不要将自己的启动文件复制到测试用户的目录中。从头开始编写新的启动文件。

当你认为自己的设置可以正常工作时,以新测试用户的身份通过所有可能的方式(控制台、远程等)登录系统。确保尽可能多地进行测试,包括窗口系统操作和手册页面。对测试用户满意后,复制第一个测试用户的启动文件,创建第二个测试用户。如果一切正常,你就有了一套新的启动文件,可以分发给新用户。

本节概述了新用户的合理默认值。

13.5.1 默认 shell

Linux 系统中任何新用户的默认 shell 都应该是 bash,因为:

  • 用户与用来编写 shell 脚本的 shell 进行交互。(由于许多原因,csh 是一个臭名昭著的糟糕的脚本编写工具--想都别想)。
  • bash 是 Linux 发行版的默认设置。
  • bash 使用 GNU readline 库接受输入,因此其界面与许多其他工具相同。
  • bash 可以让你对 I/O 重定向和文件句柄进行精细、易懂的控制。

不过,许多经验丰富的 Unix 向导使用 csh 或 tcsh 等 shell,只是因为他们最熟悉这些 shell,不忍心更换。当然,你可以选择任何你喜欢的 shell,但如果你没有任何偏好,请选择 bash,并将 bash 作为系统中任何新用户的默认 shell。(用户可以使用 chsh 命令更改自己的 shell,以适应个人喜好)。

还有很多其他 shell(如 rc、ksh、zsh、es 等)。有些并不适合作为初学者的 shell,但 zsh 和 fish 有时会受到正在寻找另一种 shell 的新用户的欢迎。

13.5.2 编辑器

在传统系统中,默认编辑器是 vi 或 emacs。在几乎所有 Unix 系统中,这些编辑器几乎是唯一保证存在的(或至少是可用的),这意味着从长远来看,它们给新用户带来的麻烦最少。不过,Linux 发行版通常会将 nano 配置为默认编辑器,因为它更容易被初学者使用。

与 shell 启动文件一样,应避免使用大的默认编辑器启动文件。在 .exrc 启动文件中稍微设置一下 showmatch(让 vi 显示匹配的括号)不会对任何人造成伤害,但要避免使用任何会显著改变编辑器行为或外观的功能,例如 showmode 功能、自动缩进和包边。

13.5.3 分页器

分页器是一种程序,如 less,可以一次显示一页文本。将默认的 PAGER 环境变量设置为 less 是完全合理的。

13.6 启动文件陷阱

在启动文件中避免这些陷阱:

  • 不要在 shell 启动文件中使用任何图形命令。并非所有 shell 都能在图形环境中运行。
  • 不要在 shell 启动文件中设置 DISPLAY 环境变量。我们还没研究过图形环境,但这会导致图形会话行为不端。
  • 不要在 shell 启动文件中设置终端类型。
  • 不要在默认启动文件中忽略描述性注释。
  • 不要在启动文件中运行打印到标准输出的命令。
  • 不要在 shell 启动文件中设置 LD_LIBRARY_PATH(参见第 15.1.3 节)。

13.7 其他启动主题

由于本书只涉及底层 Linux 系统,因此我们将不涉及窗口环境启动文件。这确实是一个大问题,因为登录现代 Linux 系统的显示管理器有自己的启动文件集,如 .xsession、.xinitrc 以及无穷无尽的 GNOME 和 KDE 相关项目组合。

窗口环境的选择似乎令人困惑,而且在 Linux 中也没有一种通用的方法来启动窗口环境。下一章将介绍其中的一些可能性。不过,当你确定了系统的功能后,你可能会对与图形环境相关的文件有点忘乎所以。这没有问题,但不要把它带给新用户。在 shell 启动文件中保持简单的原则同样适用于 GUI 启动文件。事实上,你可能根本不需要更改 GUI 启动文件。

热门相关:新婚夜,大佬调戏娇妻上瘾了   兵王无双   火力法则   我能改变东西颜色   萌妻鲜嫩:神秘老公晚上见