• 注册
  • iOS博客 iOS博客 关注:0 内容:9

    Shell环境变量

  • 查看作者
  • 打赏作者
  • 当前位置: 职业司 > iOS开发 > iOS博客 > 正文
    • iOS博客
    • 关于Shell

      为了能对shell能够有整体的认识,我们需要先简单介绍下Linux系统 。

      Linux系统

      Linux系统主要分四部分:

      1. Linux内核
      2. GNU工具
      3. 图形桌面化环境
      4. 应用软件

      Shell环境变量

      Linux内核

      Linux内核主要负责以下四种功能:

      • 系统内存管理:物理内存、虚拟内存
      • 软件程序管理:Linux操作系统将运行中的程序称为进程。内核控制着Linux系统如何管理运行在系统上的所有进程。内核创建了第一个进程(称为init进程)来启动系统上所有其他进程,Linux使用一个表来管理在系统开机时要自动启动的进程。Linux操作系统的init系统采用了运行级。运行级决定了init进程运行/etc/inittab文件或 /etc/rcX.d目录中定义好的某些特定类型的进程(X代表运行级)。Linux操作系统有5个启动运行级。每个启动运行级便是一种启动模式。
      • 硬件设备管理:内核的另一职责是管理硬件设备。任何Linux系统需要与之通信的设备,都需要在内核代码中加入其驱动程序代码。驱动程序代码相当于应用程序和硬件设备的中间人,允许内核与设备之 间交换数据。
      • 文件系统管理:不同于其他一些操作系统,Linux内核支持通过不同类型的文件系统从硬盘中读写数据。

      GNU

      操作系统用以执行一些标准功能,比如控制文件和程序的工具。Linus在创建Linux系统内核时,没有可用的系统工具。GNU是由GNU组织(GNUGNU’s Not Unix的缩写)开发了一套完整的Unix工具,是开源的,但没有运行它们的内核系统。于是将LinusLinux内核和GNU操作系统工具整合起来,就产生了一款完整的、功能丰富的免费操作系统:GNU/Linux系统(为了感谢GNU组织)也称:Linux系统。

      GNU分两部分,一部分为核心GNU工具(core utilities),由处理文件、操作文本、管理进程三部分工具包组成;另一部分便是Shell

      Shell简介

      Shell是一种特殊的交互式工具。它为用户提供了启动程序、管理文件系统中的文件以及运行在Linux系统上的进程的途径。也就是Shell负责将命令行中输入的文本命令,进行解释,并传递到内核进行执行的工具,也可称解释器。

      Shell的核心是命令行提示符。命令行提示符是Shell负责交互的部分,它允许你输入文本命令,然后解释命令,并在内核中执行。将多个shell命令放入文件中作为程序执行,这个文件便被称为Shell 脚本。

      Linux系统上,通常有好几种Linux shell可用。不同的shell有不同的特性,有些更利于创建脚本,有些则更利于管理进程。所有Linux发行版(完整的Linux系统包)默认的shell都是bash shell

      bash shellGNU组织开发,被当作标准Unix shell——Bourne shell(以创建者的名字命名)的替代品。bash shell的名称就是针对Bourne shell的拼写所玩的一个文字游戏,称为Bourne again shell。总结:sh是标准,bashsh的替代品。除了bash shellLinux中常见的几种不同shell有:

      • ash:一种运行在内存受限环境中简单的轻量级shell,但与bash shell完全兼容。
      • korn:一种与Bourne shell兼容的编程shell,但支持如关联数组和浮点运算等一些高级的编程特性。
      • tcsh:一种将C语言中的一些元素引入到shell脚本中的shell
      • zsh:一种结合了bashtcshkorn的特性,同时提供高级编程特性、共享历史文件和主题化提示符的高级 shell

      macOS Catalina 版开始,苹果的Mac系统将使用zsh作为默认登录 Shell 和交互式 Shell。具体请看官网。

      环境变量

      这一部分将基于bash shell展开陈述。

      bash shell中使用环境变量在内存中存储有关shell会话和工作环境的数据,以便程序或shell中运行的脚本能够访问到它们。

      bash shell中的环境变量主要有两种:全局变量与局部变量。查看系统中所有全局变量,可以使用envprintenv命令;要显示个别环境变量的值,可以使用printenv命令,但是不能用env命令。

      #查看shell个别全局变量
      printenv HOME
      #查看shell个别全局变量:通过echo 以变量的形式输出
      echo $HOME
      复制代码

      系统的环境都是大写,定义属于用户自己局部变量时统一使用小写,避免冲突。

      定义局部变量

      定义形式如下:

      variable=Hello
      echo $variable #输出:Hello
      复制代码

      **重要:变量名、等号和值之间没有空格。**如果在赋值表达式中加上了空格, bash shell就会把值当成一个单独的命令,变量值有空格需要使用引号。

      variable="Hello word"
      echo $variable #输出:Hello word
      复制代码

      定义全局变量

      在设定全局环境变量的进程所创建的子进程中,该全局变量都是可见的;创建全局环境变量的方法是先创建一个局部环境变量,然后再把它导出到全局环境中;父shell定义的全局变量,子shell的修改不会影响父shell的值。示例如下:

      variable="global variable ~~~~"
      export variable
      #开启子shell
      bash
      #子shell 输出一下
      echo $variable #global variable ~~~~
      #子shell修改
      variable="子shell修改"
      #子shell 输出一下
      echo $variable #输出:子shell修改
      #导出
      export variable
      #退出子shell
      exit
      #父shell输出
      echo $variable #子shell的修改不会影响父shell:global variable ~~~~
      复制代码

      删除全局变量

      使用如下命令:

      #删除
      unset variable
      复制代码

      需要注意的是在子shell中是无法删除父shell创建的全局变量。

      默认全局变量

      默认情况下,bash shell会用一些特定的环境变量来定义系统环境。这些变量在你的Linux系统上都已经设置好了,只管放心使用。bash shell源自当初的Unix Bourne shell,因此也保留了Unix Bourne shell里定义的那些环境变量。
      列举几个比较常见的环境变量:

      • CDPATH:冒号分隔的目录列表,作为cd命令的搜索路径
      • HOME:当前用户的主目录
      • PATHshell查找命令的目录列表,由冒号分隔
      • BASH:当前shell实例的全路径名
      • PWD:当前工作目录

      设置PATH变量

      当我们在shell命令行界面中输入一个外部命令时,shell必须搜索系统来找到对应的程序。PATH环境变量定义了用于进行命令和程序查找的目录:

      #输出下
      echo $PATH
      #结果
      /Users/*/.rvm/gems/ruby-2.3.0/bin:
      /Users/*/.rvm/gems/ruby-2.3.0@global/bin:
      /Users/*/.rvm/rubies/ruby-2.3.0/bin:
      /Users/*/Desktop/development/flutter/bin:
      /usr/local/bin:
      /usr/bin:
      /bin:
      /usr/sbin:
      /sbin:
      /Users/*/.rvm/bin
      复制代码

      输出的结果中显示了有10个可供shell用来查找命令和程序的路径。PATH中的目录使用冒号分隔。这些路径下分别都存放了不同的命令和程序,举个/bin的示例:
      Shell环境变量

      如果命令或者程序的路径没有包括在PATH变量中,则不使用绝对路径的情况下,shell是没法找到该程序的。

      **问题:**应用程序放置可执行文件的目录常常不在PATH环境变量所包含的目录中。

      **解决:**是保证PATH环境变量包含了所有存放应用程序的目录。可以把新的搜索目录添加到现有的PATH环境变量中,无需从头定义。PATH中各个目录之间是用冒号分隔的,我们只需要引用原来的PATH值,然后再给这个字符串添加新目录就行了。

      举例终端启用flutter命令:

      #查看path
      echo $PATH
      #结果不包含:/Users/*/Desktop/development/flutter/bin:
      #通过终端启用
      PATH=$PATH:~/Desktop/development/flutter/bin
      #再次查看
      echo $PATH
      #结果包含:/Users/*/Desktop/development/flutter/bin:
      #执行flutter
      flutter -v
      #不再提示找不到命令。
      复制代码

      值得注意的是:对PATH变量的修改只能持续到退出或重启终端系统。这种效果并不能一直持续。如何让这种效果持续?

      为了解决这个问题,我们需要了解一些关于定位环境变量的知识。

      在我们登入Linux系统启动一个bash shell时,默认情况下bash会在几个文件中查找命令。这些文件叫作启动文件或环境文件bash检查的启动文件取决于你启动bash shell的方式。启动bash shell3种方式:

      • 登录时作为默认登录shell
      • 作为非登录shell的交互式shell
      • 作为运行脚本的非交互shell

      默认登录shell

      当我们登录Linux系统时,bash shell会作为登录shell启动。登录shell会从5个不同的启动文件里读取命令:

      1. /etc/profile
      #/etc/profile启动文件内容
      # System-wide .profile for sh(1)
      if [ -x /usr/libexec/path_helper ]; then
      eval `/usr/libexec/path_helper -s`
      fi
      if [ "${BASH-no}" != "no" ]; then
      [ -r /etc/bashrc ] && . /etc/bashrc
      fi
      复制代码
      1. $HOME/.bash_profile
      2. $HOME/.bashrc
      #macOS系统中.bashrc启动文件内容,非登录的交互式shell会以此为启动文件的。
      export PATH="$PATH:$HOME/.rvm/bin"
      复制代码
      1. $HOME/.bash_login
      2. $HOME/.profile

      /etc/profile文件是系统上默认的bash shell的主启动文件。系统上的每个用户登录时都会执行这个启动文件。另外4个启动文件是针对用户的,提供一个用户专属的启动文件来定义该用户所用到的环境变量,可根据个人需求定制,且都是隐藏文件。它们位于用户的HOME目录下,所以每个用户都可以编辑这些文件并添加自己的环境变 量,这些环境变量会在每次启动bash shell会话时生效。其中25我们在macOS中是比较熟悉的。

      shell会按照下列顺序,运行第一个被找到的文件,余下的则被忽略(不会重复):
      $HOME/.bash_profile=>$HOME/.bash_login=>$HOME/.profile 注:$HOME和波浪号~作用一样,都代表用户目录。正是因为此规则的存在,我们有些时候只需要在$HOME/.profile中配置我们的PATH即可。

      非登录的交互式shell

      不是登录时启动的shell称为交互式shell。比如:在命令行提示符下敲入bash时启动。
      bash是作为交互式shell启动,则不会访问/etc/profile文件,只会检查用户目录$HOME下的.bashrc文件。

      运行脚本的非交互shell

      非交互shell,系统执行shell脚本时会使用。不同的地方在于它没有命令行提示符。但是当我们在系统上运行脚本时,可能希望运行一些特定启动的命令。为了处理这种情况,bash shell提供了BASH_ENV环境变量。当shell启动一个非交互式shell进程时,它会检查这个环境变量来查看要执行的启动文件。

      macOS系统下运行echo $BASH_ENV查看,这个环境变量并未被设置。如果BASH_ENV变量没有设置,shell脚本如何获得它们的环境变量呢?

      • shell可以继承父shell到处的环境变量;但需要注意的是父shell中设置但却未export的变量,属于局部变量,子shell是无法获取的。也就是说执行脚本时,采用bash命令开启子shell便可以解决这个问题。
      • 不启动子shell的脚本,变量已经存在于当前shell中。

      环境变量持久化

      Linux在大多数发行版中,存储个人用户永久性bash shell变量的地方是$HOME/.bashrc文件。这一 点适用于所有类型的shell进程。但如果设置了BASH_ENV变量,那么除非BASH_ENV指向的是 $HOME/.bashrc,否则应该将非交互式shell的用户变量放在别的地方。

      macOS系统中,存储个人用户永久性bash shell变量的地方,便是对应的环境文件:~/.profile~/.bash_profile~/.bashrc(交互式shell生效)。其中~/.profile~/.bash_profile任意一个都可以定义我们的永久性bash shell变量。

      #在`~/.profile`文件中定义
      export LOVE="全局可用的环境变量love"
      PEACE="局部环境变量,子shell不可用"
      #在`~/.bash_profile`文件中定义
      export SHARE="全局可用的环境变量share"
      QI="局部环境变量,子shell不可用"
      #终端shell,查看全局变量
      env
      #输出
      LOVE=全局可用的环境变量love
      SHARE=全局可用的环境变量share
      #终端shell,查看永久局部变量
      echo $PEACE
      echo $QI
      #输出
      局部环境变量,子shell不可用
      #开启非登陆交互式shell
      bash
      #子shell,查看可用全局变量
      env
      #输出
      LOVE=全局可用的环境变量love
      SHARE=全局可用的环境变量share
      #子shell,查看可用的父Shell的局部变量
      echo $PEACE
      echo $QI
      #输出为空
      复制代码

      关于~/.bashrc,作为非登录式交互shell的启动文件,仅对非登录式交互shell生效:

      #在`~/.bashrc`配置
      export CHILD="子shell可用"
      #重新打开终端,输入
      env
      #or
      echo $CHILD
      #都输出:空
      #开启子shell(交互式shell)
      bash
      #查看子shell的全局变量
      env
      #or
      echo $CHILD
      #输出
      CHILD=子shell可用
      子shell可用
      #再次开启子shell
      bash
      #输入
      env
      #or
      echo $CHILD
      #输出
      CHILD=子shell可用
      子shell可用
      #如果`~/.bashrc`文件中配置
      CHILD="子shell可用"
      #输入
      env
      #输出:空
      #输入
      echo $CHILD
      #输出
      子shell可用
      #再次开启子shell,`CHILD`变量将不再生效
      复制代码

      数组变量

      数组变量:环境变量设置多个值,放置在括号中,且值与值之间用空格隔开。

      #定义数组变量
      ARRAY_VAR=(one two three)
      #输出数组变量
      echo $ARRAY_VAR
      #不会全部输出,只会输出数组变量中第一个元素
      one
      复制代码

      要引用数组变量中的某个元素,就必须用代表它在数组中位置的数值索引值。索引值要用方括号括起来:

      echo ${ARRAY_VAR[2]}
      #输出
      three
      #显示整个数组
      echo ${ARRAY_VAR[*]}
      复制代码

      可以用unset命令删除数组中的某个值,但是要小心。比如:

      #删除索引为1的元素
      unset ARRAY_VAR[1]
      #输出整个数组
      echo ${ARRAY_VAR[*]}
      #删除成功
      one three
      #输出数组中索引为1的元素
      echo ${ARRAY_VAR[1]}
      #结果为:空
      #输出索引为2的元素
      echo ${ARRAY_VAR[2]}
      #结果
      3
      复制代码

      参考资料:
      Linux命令行与shell脚本编程大全

      请登录之后再进行评论

      登录

      手机阅读天地(APP)

      • 微信公众号
      • 微信小程序
      • 安卓APP
      手机浏览,惊喜多多
      匿名树洞,说我想说!
      问答悬赏,VIP可见!
      密码可见,回复可见!
      即时聊天、群聊互动!
      宠物孵化,赠送礼物!
      动态像框,专属头衔!
      挑战/抽奖,金币送不停!
      赶紧体会下,不会让你失望!
    • 实时动态
    • 签到
    • 做任务
    • 发表内容
    • 偏好设置
    • 到底部
    • 帖子间隔 侧栏位置:
    • 还没有账号?点这里立即注册