shell 及 环境变量

2016/3/16 12:17:18

汇总 3 篇。此处 shell 指工具,不涉及 shell 编程、脚本等知识。

shell 和简单操作

shell 简介

Shell 是什么呢? 确切地说,Shell 就是一个命令行解释器,它的作用就是遵循一定的语法将输入的命令加以解释并传给操作系统内核,它为用户提供了一个向 Linux 发送请求以便运行程序的接口,用户可以用 Shell 来启动、挂起、停止甚至是编写一些程序。

Linux Shell的种类 很多,目前流行的 Shell 包括 ash、bash、ksh、csh、zsh 等,用户可以通过查看 /etc/shells 文件中的内容来查看自己主机中当前有哪些种类的 Shell。

定义 shell 变量

定义变量

  • “取值包含空格,必须用双引号括起来”√,
  • “shell变量可以用大小写字母”,但是环境变量一般大写,个人声明变量一般小写,以作区分。

echo 显示变量

使用 echo 命令可以显示单个变量取值,并在变量名前加 $,例如:

13

备注:红色矩形框标注部分,为正确方式。

其中 ,echo “$LOGNAME” 并不是合理书写方式,只是效果相同而已。取 $LOGNAME 值 rmq ,然后 echo “rmq”,所以也是输出 rmq。

131

其他

以下内容在 shell 脚本中使用得更多一些。对于不接触 shell 编程,只关心怎么设置环境变量的人来说并不需要了解。放在这里也只是当初花费了时间和精力,不忍当 垃圾 一样丢掉。

背景

角度A:由简入繁

  1. 我们启动一个 shell 实例(通常是 bash),在其中以 var=value 的形式定义变量,那么这个变量 var 的作用域只限于当前 shell,既不能在另一实例(同类型 shell、不同类型 shell)中使用,也不能传递给当前实例的子进程(由当前 shell 实例启动的进程);生存周期和当前实例的生存周期相同(如果不使用 unset 命令清除此变量的话),即随着实例的关闭而消失。

  2. export var 之后呢?Exporting a variable causes the variable to be inherited,This is the most common way of setting variables for use of subsequently started processes in a shell。但是其他特性不变。


    以上都是临时的;
    每种 shell 都有自己特有的变量,比如 bash shell 中的 BASH,这些变量处于“shell类型”这个层次。
    以下都是永久的。


  3. 那么如何让一个变量在两个 shell中(同类型)同时起作用呢?或者在关闭并重新打开一个shell时,如何使之前定义的变量依旧有效呢?

    ——持久化的话可以落盘成文件。针对 bash shell,我们可以将变量定义在 ~/.bashrc 文件中,每一个 non-login interactive shell 在启动时都会首先读入这个配置文件,而 login shell 在登录时会读入 ~/.profile(一般在此文件中包含 .bashrc 文件)。因为只有在 shell 启动 /login 时才会读入,所以在 shell 中更改配置文件后并不会立即生效,我们可以 exit 重启(针对 non-login shell)或者 logout 重新 login(针对 login shell),或者使用 source filename 命令重新执行刚修改的初始化文件,使之立即生效。

    理解到这,已经足够我们日常使用 linux了。因为一方面我们只使用系统默认的 shell(linux 下基本都是 bash),另一方面我们也不是系统管理员,没有 root 权限做系统层面的维护。

  4. 那么如何让变量在不同类型 shell 中都有效?如何让变量在不同用户中都有效?不能同步修改所有类型 shell 的配置文件,同步修改所有用户的配置文件吧

    ——针对不同类型 shell,可以修改 ~/.profile 文件或者 /etc/profile 文件;针对所有用户,可以修改 /etc/profile 文件。ps:针对多用户的 bash shell,可以修改 /etc/bashrc 文件。

角度B:整体回顾

经常见到“环境变量”一词,那么这种变量究竟有什么特殊之处?它的定义又是怎样的呢?

  1. 环境变量是操作系统环境设置的变量,适用于整个系统的用户进程;
  2. 环境变量可以在命令中设置,但是用户注销的时候将会丢失这些设置值;
  3. 若要重复适用,则最好在 .profile 中定义;环境变量的使用与本地变量的使用方法相同,
  4. 但是在使用之前,必须用 export 命令导出。

核心在于弄清楚局部变量和全局变量的作用范围、生存周期,以及局部变量可以导出为全局变量,进一步可持久化存储到配置文件中。

按变量的生存周期来划分,Linux 变量可分为两类:

  • 永久的:需要修改配置文件,变量永久生效。
  • 临时的:使用 export 命令声明即可,变量在关闭 shell 时失效。

故此,可分出:

  1. 永久全局变量:永久代表持久化为文件,全局代表在各种 shell、跨应用使用,(文件名中无“bash”)
  2. 永久局部变量:一般指各种 shell(例如 bash)在自身配置文件中储存了的变量,只能在 bash 中使用,不能再 csh 等其他 shell 中使用,(文件名中包含“bash”);
  3. 临时局部变量:在 shell 中通过 key=value 定义的变量;
  4. 临时全局变量:将临时局部变量通过 export 命令导出,即可全局使用,但因为未存储到文件中,所以在用户注销,下次登录之后就会失效;

所以,环境变量其实没有什么特殊之处。不过我们说环境变量一般还是指全局的:

全局变量,即环境变量(临时的&永久的)。局部变量又称 shell 私有变量。所谓永久其实就是开机/登录/打开shell时把文件中诸多 export key=value 命令先执行。


知道以上区别,就知其所以然,不必只知其然而较真死记硬背了。也不必较真在某一句话里环境变量用的不恰当啊什么的了,不必较真变量分类。难得糊涂!

配置文件

先声明一点,在下文中不再叙述:系统目录(/etc)中的配置文件信息对所有用户有效;用户主目录下的配置文件信息只对当前用户有效。

Debian环境变量文件描述

以Debian8.1 Jessie为例,截图如下:

debian 8.1

来源:/etc/profile

debian 8.1

来源:~/.profile

可以从中看到“登录 shell”的概念,与之对应的就是“非登录 shell”。

很明确的指出了这两个配置文件,是用于“登录 shell”的。在“非登录 shell”中是不会读取/执行这两个文件的,也就是说在这两个文件中配置的环境变量等信息在“非登录 shell”中是不奏效的。

另外,这两文件都是针对系统中所有 shell 的,包括但不限于常用的 bash、sh、ksh 等。

但是针对 bash,有一点特殊的地方:如果在用户主目录下存在 .bash_profile 或者 .bash_login 文件,则 .profile 是不会被读取的。强调优先级,且只读取其中一个。

debian 8.1

来源:/etc/bash.bashrc

debian 8.1

来源:~/.bashrc

可以从中看到“交互式 shell”的概念,与之对应的就是“非交互式 shell”。下图中也出现了“非登录 shell”字样。

首先明确,这两个文件值针对 bash 的,对其他 shell 无效。且这两个文件被用于“非登录交互式 shell”。

那么问题来了:(只针对 bash)

login shell non-login shell
interactive shell .profile √ << .bashrc × .profile × .bashrc √
non-interactive shell .profile √ << .bashrc × .profile × .bashrc ×

可以看到:

  1. 对于“非登录且非交互式的 shell”,是没有配置方法的。不过貌似我们也不需要。
  2. /etc/bash.bashrc 和 ~/.bashrc 文件对于“登录 shell” 是无效的。
  3. /etc/profile 和 ~/.profile 文件对于“非登录 shell” 是无效的。

(non-)login/interactive

第一章只是复述了系统文件自带的描述,并无意外的知识。但是什么样是“login shell”,什么又是“non-login shell”呢?什么是“interactive shell”,什么又是“non-interactive shell”呢?

  1. 可以参考“交互式SHELL和非交互式SHELL、登录SHELL和非登录SHELL的区别”,这篇帖子讲的还是非常不错的。

    特别强调一点:“在 Gnome 或 KDE 中打开一个“终端”(terminal)窗口程序也是一个非登录 shell。”

  2. 我越来越感觉到“stackoverflow-differences between login shell and interactive shell ”网站对于 C++ 开发者的重要了。

    重点关注最后一段话,我想答主提到“shell scripts”时,等价表示“非登录且非交互式”。

  3. 也可以看看“login shell与non-login shell的区别”,这篇帖子有几处表述不恰当的地方,记录如下:

    • 在提到login shell启动读取配置文件顺序时,没有区分bash shell 和shell 。两者的区别是需要强调的!
    • “如果使用命令”sh”调用bash……”,我想作者通过这一句是想表达调用bash脚本,表明“非交互式shell”

    (依旧)转载这篇帖子最重要的原因是他告诉了我们以下知识

    • “非交互式的non-login shell不读取上述所有配置文件,而是查找环境变量BASH_ENV,读取并执行 BASH_ENV 指向的文件中的命令。”
    • “通常我们要定制一些配置时,将配置写在/.bashrc中,然后在/.bash_profile中读取~/.bashrc,这样可以保证login shell和交互式non-login shell得到相同的配置。”

    debian 8.1

    来源:~/.profile

    debian 8.1

    来源:/etc/profile

  4. 懂得了以上,其中是非论断 就很 easy 了。

    debian 8.1

Ubuntu 环境变量文件介绍

系统级:

debian 8.1

  • /etc/profile:该文件是用户登录时,操作系统定制用户环境时使用的第一个文件,应用于登录到系统的每一个用户。该文件一般是调用/etc/bash.bashrc文件。
  • /etc/bash.bashrc:系统级的bashrc文件。
  • /etc/environment:在登录时操作系统使用的第二个文件,系统在读取你自己的profile前,设置环境文件的环境变量。(这个文件大师我还没有研究过)

用户级(这些文件处于 home 目录下):

debian 8.1

  • ~/.profile:每个用户都可使用该文件输入专用于自己使用的shell信息,当用户登录时,该文件仅仅执行一次!默认情况下,他设置一些环境变量,执行用户的.bashrc文件。这里是推荐放置个人设置的地方
  • ~/.bashrc:该文件包含专用于你的bash shell的bash信息,当登录时以及每次打开新的shell时,该该文件被读取。不推荐放到这儿,因为每开一个shell,这个文件会读取一次,效率肯定有影响。
  • ~/.bash_profile or ~./bash_login:这里没有引用作者的,下面会提到
  • ~/.pam_environment:用户级的环境变量设置文件,没有做测试,不知道管不管用。

小结

通过上面的文件介绍,就能明白我们需要设置环境变量的时候,需要修改什么文件,要想对所有的用户生效,那就需要设置系统级的环境变量。反之,需要修改用户级的文件(最好是修改.profile文件,理由上面已经讲了)。

另外,我使用的是 Ubuntu10.04,之前在查找资料设置用户级环境变量的时候,有资料说要修改 ~.bash_profile 文件,但是在 ubuntu10.04 系统中是没有该文件。经查找,在 ubuntu 官网 上找到了这个文件的说明:

/.bash_profile or ~./bash_login - If one of these file exist, bash executes it rather then “/.profile” when it is started as a login shell. (Bash will prefer “/.bash_profile” to “/.bash_login”). However, these files won’t influence a graphical session by default.

意思应该是说当这个文件存在时,在登录 shell 时会读取 ./bash_profile 文件,而不是 .profile 文件。我认为该文件实现的目的跟 .profile 文件是一样的,当查找的资料中需要你修改 .bash_profile 文件,但却你没有该文件的时候,也可以修改 .profile 来完成实现。

以上仅为个人观点,如有错误请批评指正!感激涕零……

设置环境变量

以上你都看懂了,你还不会设置环境变量吗?

有一篇讲解还比较到位的帖子:Linux设置环境变量小结