Linux shell编程学习 -- 基础篇 - shell与环境

Contents

        • 理解shell
          • shell的类型
          • shell的父子关系
          • 进程列表
          • 子shell用法
          • shell的内建命令
        • Linux环境变量
          • 环境变量
          • 默认shell环境变量
          • 定位系统环境变量
          • 数组变量
        • 总结

学习目标:从认识Linux命令行基础开始,一直到写出自己的shell脚本

理解shell

    要想理解shell,需要先理解CLI。shell不单单是一种CLI,它是一个时刻都在运行的复杂式交互程序。

shell的类型

    系统启动什么样的shell程序取决于用户个人ID的配置,在/etc/passwd文件中。此处以bash shell为例,bash shell程序位于/bin目录内。它是一个可执行程序。
    默认的交互shell会在用户登录某个虚拟控制台中断或在GUI中运行终端仿真器时启动。不过还有另外一个默认的shell是/bin/sh,它作为默认的系统shell,用于那些需要在启动时使用的系统shell脚本。
    除此之外,还有dash、tcsh、csh等其他shell。

shell的父子关系

    用于登录某个虚拟控制器中断或在GUI中运行终端仿真器时所启动的默认的交互shell,是一个父shell。在CLI提示符后输入/bin/bash命令或其他等效的bash命令时,会创建一个新的shell程序。这个shell程序被称为子shell。子shell也拥有CLI提示符,同样会等待命令输入。
Linux shell编程学习 -- 基础篇 - shell与环境_第1张图片
    以下就运行了两个shell进程,输入/bin/sh命令后,一个子shell命令就出现了;而ps -f命令就是在子shell中运行的。父shell进程2287,子shell进程5661,进程的详细信息中的PID和PPID显示了它们之间的关系。但需要注意的是,在生成子shell进程时,只有部分父进程的环境会被复制到子shell环境中。
Linux shell编程学习 -- 基础篇 - shell与环境_第2张图片
    子shell可以从父shell中创建,也可以从另一个子shell中创建,使用ps --forest命令可以展示这些子shell间的嵌套关系。
Linux shell编程学习 -- 基础篇 - shell与环境_第3张图片

进程列表

    可以在一行中指定要一次运行的一系列命令,可以通过命令列表来实现,命令你列表就是在需要指定的命令间加上分号(;)。但如果命令列表要想成为进程列表,需要加上括号()

尽管多出来的括号看起来没有什么太大的不同,但是起到的效果确实非同一般。括号的加入使命令列表变成了进程列表,生成了一个子shell来执行对应的命令
进程列表是一种命令分组。另一种命令分组是将命令放入到花括号中,并在命令列表尾部加上分号(;)。语法为{command; }。但是使用花括号进行命令分组并不会像进程列表那样创建出子shell。
要想知道是否生成了子shell,可以使用环境变量 $BASH_SUBSHELL,如果该值返回0,就表示没有子shell。如果返回1或者更大的数字,就表明存在子shell。
Linux shell编程学习 -- 基础篇 - shell与环境_第4张图片    在shell脚本中,经常使用子shell进行多进程处理。但是采用子shell的成本不菲,会明显拖慢处理速度。在交互式的CLI shell会话中,子shell同样存在问题。它并非真正的多进程处理,因为终端控制着子shell的I/O。

子shell用法

    后台模式
    在后台模式中运行命令可以在处理命令的同时让出CLI,以供他用。演示后台模式的一个经典命令就是sleep。sleep命令接受一个参数,该参数是你希望进程等待(睡眠)的秒数。这个命令在脚本中常用于引入一段时间的暂停。命令sleep 10会将会话暂停10秒钟,然后返回shell CLI提示符。要想将命令置入后台模式,可以在命令末尾加上字符&
    当一个命令置入后台后,会出现两条信息,第一条信息是显示在方括号中的后台作业号,一个是后台作业的进程ID。
Linux shell编程学习 -- 基础篇 - shell与环境_第5张图片
    除了ps命令,也可以使用jobs命令来显示后台作业信息。jobs命令可以显示出当前运行在后台模式中的所有用户的进程。

    进程列表置入后台
    在CLI中运用子shell的创造性方法之一就是将进程列表置入后台模式。这样既可以在后台处理繁重的工作,也不会让子shell的I/O受制于终端。比较典型的例子是使用tar命令。

(tar -cf Rich.tar /home/rich ; tar -cf My.tar /home/pool)&

    协程
    协程可以同时做两件事。它在后台生成一个子shell,并在这个子shell中执行命令,要使用协程处理,得使用coproc命令,还有要在子shell中执行的命令。
    除了会创建子shell之外,协程基本上就是将命令置入后台模式。当输入coproc命令及其参数之后,就会发现启用一个后台作业,屏幕上会显示出后台作业号以及进程ID。
    jobs命令能够显示出协程的处理状态。
    将协程与进程列表结合起来可以产生嵌套的子shell。只需要输入进程列表,然后把命令coproc放在前面就行了。但是生成子shell的成本不低,而且速度还慢。创建嵌套子shell更会有不好的影响。

shell的内建命令

    外部命令
    外部命令,有时候也被称为文件系统命令,是存在于bash shell之外的程序。他们并不是shell程序的一部分。外部命令程序通常位于/bin、/usr/bin、/sbin或者/usr/sbin中。

ps命令就是一个外部命令,可以通过which和type命令找到

    当外部命令执行时,会创建一个子进程。这种操作被称为“衍生”。外部命令ps很方便的显示出它的父进程以及自己所对应的衍生子进程。当进程必须执行衍生操作时,它需要花费时间和精力来设置子进程的环境。所以说,外部命令多少还是有代价的。
Linux shell编程学习 -- 基础篇 - shell与环境_第6张图片
    内建命令
    内建命令和外部命令的区别在于前者不需要使用子进程来执行。它们已经和shell编译成一体,作为shell工具的组成部分存在。不需要借助外部程序文件来运行。因此内建命令的执行速度要更快、效率更高。

cd 和 exit命令都内建于bash shell。可以利用type命令来了解某个命令是否是内建
Linux shell编程学习 -- 基础篇 - shell与环境_第7张图片

    但是需要注意的是,有些命令有多种实现。例如echo和pwd既有内建命令也有外部命令,二者略有不同。

命令type -a可以显示出每个命令的两种实现。但是which命令只会显示外部命令文件。
对于多种实现的命令,如果想要使用其外部命令实现,直接指明对应的文件就行,比如/bin/pwd

  • 内建命令history,用于追踪bash shell中使用过的命令
  • 内建命令alias,允许用户使用自定义别名常用的命令(及其参数),但是仅在它所定义的shell进程中才有效
Linux环境变量
环境变量

    bash shell用一个叫作环境变量的特性来存储有关shell会话和工作环境的信息,环境变量分成两类
    全局变量
    全部环境变量对于shell会话和所有生成的子shell都是可见的。系统环境变量基本上都是使用全大写字母,以区别于普通用户的环境变量。

使用env或printenv命令可以打印出环境变量

    局部变量
    局部环境变量只对创建它们的shell可见。

使用set命令会显示出全局变量、局部变量以及用户定义变量。它还会按照字母顺序对结果进行排序

    设置用户变量
    按照bash shell的标准惯例,如果是自己创建的局部变量或者是shell脚本,应该使用小写字母。避免重定义系统环境变量。
    局部用户定义变量:仅在当前shell中可用
    全局用户定义变量:在设定全局环境变量的进程所创建的子进程中,该变量都是可见的。创建全局环境变量的方法是先创建一个局部环境变量,然后再把它导出到全局环境中。这个过程通过export命令来完成,变量名前不需要加$
    删除环境变量:使用unset命令即可完成这个操作

在设计环境变量名时,什么时候需要使用 , 什 么 时 候 不 需 要 ? 如 果 要 使 用 变 量 , 使 用 , 什么时候不需要? 如果要使用变量,使用 ,使使,如果要操作变量,不使用$

默认shell环境变量

    bash shell源自Unix Bourne shell,因此也保留了Unix Bourne shell里面定义的那些环境变量,常用的如下:

变量 描述
CDPATH 冒号分割的目录列表,作为cd命令的搜索路径
HOME 当前用户的主目录
IFS shell用来将文本字符串分割成字段的一系列字符
OPTARG getopts命令处理的最后一个选项参数值
OPTIND getopts命令处理的最后一个选项参数的索引号
PATH shell查找命令的目录列表,由冒号分割
PS1 shell命令行界面的主提示符
PS2 shell命令行界面的次提示符

    除了默认的Bourne的环境变量,bash shell还提供一些自由的变量。

变量 描述
BASH 当前shell实例的全路径名
ENV 用户配置的环境变量
LANG shell的语言环境类别
LC_ALL 定义一个语言环境类别,能够覆盖LANG变量
LCD_COLOATE 设置对字符串排序时用的排序规则
LC_CTYPE 决定如何解释出现在文件名扩展和模式匹配中的字符
LC_NUMERIC 决定着格式化数字时采用的语言环境设置
PWD 当前工作目录
SHELL bash shell的全路径名
UID 当前用户的真实用户ID(数字形式)
定位系统环境变量

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

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

    登录shell
bash shell作为登录shell启动会从以下5个不同的启动文件里读取命令

/etc/profile: 系统上默认的bash shell的主启动文件,每个用户登录时都会执行
$HOME/.bin_profile
$HOME/.bashrc
$HOME/.bash_login
$HOME/.profile

    交互式shell
    交互式shell启动时不会访问/etc/profile文件,只会检查用户HOME目录下的.bashrc文件
    .bashrc文件有两个作用:一是查看/etc目录下通用的bashrc文件,二是为用户提供一个定制自己的命令别名和私有脚本函数的地方

    非交互式shell
    系统执行shell脚本时用的就是这种shell。不同的地方在于它没有命令行提示符。但是在系统上运行脚本时,也许希望能够运行一些特定启动的命令。为了处理这种情况,bash shell提供了BASH_ENV环境变量。当shell启动一个非交互式shell进程时,它会检查这个环境变量来查看要执行的启动文件。如果有指定的文件,shell会执行改文件里的命令,这通常包括shell脚本变量设置。

数组变量

    环境变量有一个很好的特性就是,它们可以作为数组使用。数组是能够存储多个值的变量,这些值可以单独引用,也可以作为整个数组来引用。

环境变量的索引值都是从零开始。

mytest=(one two three four five)

echo $mytest
one

echo $(mytest[2])
three

echo $(mytest[*])
one two three four five
总结

    全局环境变量可以在对其作出定义的父进程所创建的子进程中使用。局部环境变量只能在定义他们的进程中使用。
    Linux系统使用全局环境变量和局部换将变量存储系统环境信息。可以通过shell的命令行界面或者在shell脚本中访问这些信息。PATH环境变量定义了bash shell在查找可执行可执行命令时的搜索目录。可以修改PATH环境变量来添加自己的搜索目录,以方便程序的运行。
    也可以创建自用的全局和局部环境变量。一旦创造了环境变量,它在整个shell会话中就都是可用的。
    bash shell会在启动时执行几个启动文件。这些启动文件包含了环境变量的定义,可用于为每个bash会话设置标准环境变量。每次登录Linux系统,bash shell都会访问/etc/profile启动文件以及3个针对每个用户的本地启动文件:HOME/.bash_profile、HOME/.bash_login和 HOME/.profile 用户可以在这些文件中定制自己想要的环境变量和启动脚本。

你可能感兴趣的:(Linux,shell编程,linux,shell)