• 第二章 初识Linux Shell


    2.1 Bash Shell

    2.1.1 Bash简介

    Bash是一个与Bourne Shell兼容的,执行从标准输入设备或文件读取的命令的命令语言解释器。Bash是Bourne-Again Shell的缩写。
    Bash与原来的Unix sh shell向后兼容,并且融合了一些有用的Korn Shell和C Shell的特性。它相对于sh在编程和交互式使用两方便都做了功能改进。另外,大部分的sh脚本可以在不做修改的情况下由Bash直接运行。
    Bash具有很好的移植性。它使用在构建时发现编译平台特征的配置系统,因此可以构建在几乎任一种Unix版本上。

    2.1.2 Bash提供的改进

    Bash的语法是Bourne Shell语法的一个改进版本。在大多数情况下,Bourne Shell脚本可以被Bash正常的运行。下面列出了Bash提供的一部分改进:

    • 命令行编辑
    • 命令行补全
    • 不限制命令行历史大小
    • 不限制大小的数组
    • Bash启动文件 – 你可以运行Bash作为一个交互式登录Shell,或作为一个交互式非登录Shell。
    • 条件表达式
    • 目录堆栈 – 访问目录的历史记录
    • 限制性Shell – 更多的Shell执行的控制模式
    • Bash POSIX模式 – 使Bash行为更接近POSIX标准的规定。

    2.2 Shell在Liunx环境中的角色

    Linux环境由以下几部分构成:

    • 内核 – Linux操作系统的核心
    • Shell – 为用户和内核提供一个交互的接口
    • 终端模拟器 – 它允许用户输入命令并在屏幕上回显命令的运行结果
    • Linux桌面和窗口管理器 – Linux桌面是各种软件应用程序的集合。它包括文件管理器、窗口管理器、终端模拟器等等。

    由此可见,Shell在Linux环境中扮演了非常重要的角色,包括读取命令行、解释它的含义并执行、通过输出返回执行结果等等。

    用户登录系统时,Shell为用户自动定义唯一的工作环境,并对该环境进行维护直至用户注销。该环境将定义如身份、工作场所和正在运行的进程等特征。这些特性由指定的环境变量值定义。
    Shell环境与办公环境相似,在办公室中每个人所处环境的物理特性,如灯光合温度,但在办公环境中又有许多因素是个人特有的,如日常工作和个人工作空间,因此用户自己的工作环境就有别于其他用户的工作环境。正如一个用户的Shell环境不同于其他用户的Shell环境。
    用户工作环境还有登录环境和非登录环境之分。登录环境是指用户登录系统时的工作环境,此时的Shell对登录用户而言是主Shell。非登录环境是指用户在调用子Shell时所使用的用户环境。
    用户并不需要每次登录后都对各种环境变量进行手工设置,通过环境设置文件,用户的工作环境的设置可以在登录的时候自动由系统来完成。环境设置文件有两种,一种是系统环境设置文件,另一种是个人环境设置文件。

    1. 系统中的用户工作环境设置文件(对所有用户均生效)
      1. 登录环境设置文件:/etc/profile。
      2. 非登录环境设置文件:/etc/bashrc。
    2. 用户设置的环境设置文件(只对用户自身生效)
      1. 登录环境设置文件:$HOME/.bash_profile。
      2. 非登录环境设置文件:$HOME/.bashrc。

    2.2.1 与登录Shell相关的文件

    当Linux系统的运行级别为3级或者5级时,都需要输入用户名和密码。用户登录时Bash将会使用以下初始化文件和启动脚本:

    • /etc/profile:系统级的初始化文件,定义了一些环境变量,由登录shell调用执行。
    • /etc/bash.bashrc或/etc/bashrc:定义了一些函数和别名。
    • /etc/bash.logout:系统级的登录shell清理脚本,当登录Shell退出时执行。
    • $HOME/.bash_profile、$HOME/.bash_login、$HOME/.profile:用户个人初始化脚本,由登录Shell调用执行。
    • $HOME/.bashrc:用户个人的每个交互式Shell的启动脚本。
    • $HOME/.bash_logout:用户个人的登录Shell清理脚本,当登录Shell退出时执行。
    • $HOME/.inputrc:用户个人的由readline使用的启动脚本,定义了处理某些情况下的键盘映射。

    2.2.2 Bash启动脚本

    用户登录时自动执行的脚本只要用于设置一些环境,例如JAVA_HOME的路径。其中的一些脚本被登录shell调用,登录shell是登录系统最先执行的Shell。它设置一些环境,然后把这些环境授予非登录Shell。
    当用户登录时,登录Shell会调用如下脚本:

    • /etc/profile – 当用户在运行级别3登录系统时首先运行。
    • /etc/profile.d – 当/etc/profile运行时,会调用该目录下的一些脚本。
    • $HOME/.bash_profile、$HOME/.bash_login和$HOME/.profile – 在/etc/profile运行后,第一个存在的被运行。
    • $HOME/.bashrc – 上述脚本的中一个运行后即调用此脚本。
    • /etc/bashrc或/etc/bash.bashrc – 由$HOME/.bashrc调用运行。

    当一个交互式的非登陆Shell启动时,bash将读取并运行如下脚本:

    • $HOME/.bashrc – 如果此文件存在即被运行。
    • /etc/bashrc – 将被$HOME/.bashrc调用运行。
    • /etc/profile.d – 此目录下的脚本将被/etc/bashrc或/etc/bash.bashrc调用运行。

    Bash启动脚本主要设置的环境有:

    • 设置环境变量PATH和PS1(我们将在2.3.1节中介绍这两个变量)
    • 通过变量EDITOR设置默认的文本编辑器
    • 设置默认的umask(文件或目录的权限属性)
    • 覆盖或移除不想要的变量或别名
    • 设置别名
    • 加载函数

    2.2.3 定制自己的Bash登录脚本

    2.2.4 Bash退出脚本

    当登录Shell退出时,如果$HOEM/.bash_logout脚本存在的话,bash会读取并执行此脚本的内容。此脚本主要有如下用途:

    • 使用clear命令清理你的终端屏幕输出
    • 移除一些临时文件
    • 自动运行一些命令或脚本等

    2.2.5 定制自己的Bash退出脚本

    2.2.6 有效的登录Shell的路径

    /etc/shells是一个包含有效的登录shell全路径名的文本文件。这个文件会被chsh命令(变更你的登录shell)所使用,也可被其它程序查询使用,比如ftp服务。查看/etc/shells的内容:

    [root@hadoop102 ~]#  cat /etc/shells
    /bin/sh
    /bin/bash
    /sbin/nologin
    /usr/bin/sh
    /usr/bin/bash
    /usr/sbin/nologin
    /bin/tcsh
    /bin/csh
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    你也可以使用which命令显示shell的全路径:

    [root@hadoop102 ~]# which bash
    /usr/bin/bash
    
    • 1
    • 2

    2.3 Shell中的变量

    变量是任何程序或脚本的重要组成部分。变量为程序或脚本访问内存中的可被修改的一块数据提供了简单的方式。Linux Shell中的变量可以被指定为任意数据类型,比如文本字符串或是数值。你也可以通过修改Shell中的变量来改变Shell的样式。接下来就让我们来了解和学习一下Shell中的变量。

    2.3.1 Shell中变量的类型

    Shell中有两种变量的类型:系统变量(环境变量)和用户自定义的变量(本地变量或Shell变量)。

    1. 系统变量是由Linux Bash Shell创建和维护的变量。可以通过修改系统变量、如PS1、PATH、LANG、HISTSIZE和DISPLAY等,配置Shell的样式。常用的系统变量(环境变量)如下表:
    系统变量说明
    BASH_VERSION保存Bash实例的版本
    DISPLAY设置X display名字
    EDITOR设置默认的文本编辑器
    HISTFILE保存命令历史的文件名
    HISTFILESIZE命令历史文件所能包含的最大函数
    HISTSIZE记录在命令历史中的命令数
    HOME当前用户的主目录
    HOSTNAME你的计算机的主机名
    IFS定义Shell的内部字段分隔符,一般是空格符、制表符和换行符
    PATH搜索命令的路径。它是以冒号分隔的目录列表。
    PS1你的提示符设定
    PWD当前工作目录。由cd命令设置
    SHELL设置登录Shell的路径
    TERM设置你的登录终端的类型
    TMOUT用于设置Shell内建命令read的默认超时时间,单位为秒

    当然,你可以添加上述变量到你账号的home目录下的初始化文件中,比如~/.bash_profile文件。这样在你每次登录系统时,这些变量会被自动设置为你需要的值。
    如果要查看当前Shell的所有系统变量,可以在控制台或终端输入如下命令:

    $ env
    
    • 1

    或者

    $ printenv
    
    • 1

    你将会看到类似如下的输出结果:

    XDG_VTNR=1
    SSH_AGENT_PID=1835
    XDG_SESSION_ID=1
    HOSTNAME=hadoop100
    IMSETTINGS_INTEGRATE_DESKTOP=yes
    VTE_VERSION=5204
    TERM=xterm-256color
    SHELL=/bin/bash
    XDG_MENU_PREFIX=gnome-
    HISTSIZE=1000
    GNOME_TERMINAL_SCREEN=/org/gnome/Terminal/screen/c0186a2c_c58d_4fdc_a53b_a23c308473b7
    IMSETTINGS_MODULE=none
    USER=li
    GNOME_TERMINAL_SERVICE=:1.107
    SSH_AUTH_SOCK=/run/user/1000/keyring/ssh
    USERNAME=li
    SESSION_MANAGER=local/unix:@/tmp/.ICE-unix/1703,unix/unix:/tmp/.ICE-unix/1703
    GNOME_SHELL_SESSION_MODE=classic
    PATH=/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin
    MAIL=/var/spool/mail/li
    DESKTOP_SESSION=gnome-classic
    QT_IM_MODULE=ibus
    XDG_SESSION_TYPE=x11
    PWD=/home/li
    XMODIFIERS=@im=ibus
    LANG=zh_CN.UTF-8
    GDM_LANG=zh_CN.UTF-8
    GDMSESSION=gnome-classic
    HISTCONTROL=ignoredups
    XDG_SEAT=seat0
    HOME=/home/li
    SHLVL=2
    GNOME_DESKTOP_SESSION_ID=this-is-deprecated
    XDG_SESSION_DESKTOP=gnome-classic
    LOGNAME=li
    XDG_DATA_DIRS=/home/li/.local/share/flatpak/exports/share/:/var/lib/flatpak/exports/share/:/usr/local/share/:/usr/share/
    DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-uwrzkuJLBV,guid=3f90f6b70bfb6e9c73faf7a862fcf3e1
    LESSOPEN=||/usr/bin/lesspipe.sh %s
    WINDOWPATH=1
    XDG_RUNTIME_DIR=/run/user/1000
    DISPLAY=:0
    XDG_CURRENT_DESKTOP=GNOME-Classic:GNOME
    COLORTERM=truecolor
    XAUTHORITY=/run/gdm/auth-for-li-6t7NT7/database
    _=/usr/bin/printenv
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    1. 用户定义的变量即由用户创建和维护的变量。这一类型的变量可以使用任何有效的变量名来定义。

    如果要查看当前shell中的所有用户自定义变量和系统变量,可以在控制台上或终端上使用env命令查看:

    env
    
    • 1

    输出结果:

    XDG_VTNR=1
    SSH_AGENT_PID=1835
    XDG_SESSION_ID=1
    HOSTNAME=hadoop100
    IMSETTINGS_INTEGRATE_DESKTOP=yes
    VTE_VERSION=5204
    TERM=xterm-256color
    SHELL=/bin/bash
    XDG_MENU_PREFIX=gnome-
    HISTSIZE=1000
    GNOME_TERMINAL_SCREEN=/org/gnome/Terminal/screen/c0186a2c_c58d_4fdc_a53b_a23c308473b7
    IMSETTINGS_MODULE=none
    USER=li
    GNOME_TERMINAL_SERVICE=:1.107
    SSH_AUTH_SOCK=/run/user/1000/keyring/ssh
    USERNAME=li
    SESSION_MANAGER=local/unix:@/tmp/.ICE-unix/1703,unix/unix:/tmp/.ICE-unix/1703
    GNOME_SHELL_SESSION_MODE=classic
    PATH=/usr/local/bin:/usr/local/sbin:/usr/bin:/usr/sbin:/bin:/sbin
    MAIL=/var/spool/mail/li
    DESKTOP_SESSION=gnome-classic
    QT_IM_MODULE=ibus
    XDG_SESSION_TYPE=x11
    PWD=/home/li
    XMODIFIERS=@im=ibus
    LANG=zh_CN.UTF-8
    GDM_LANG=zh_CN.UTF-8
    GDMSESSION=gnome-classic
    HISTCONTROL=ignoredups
    XDG_SEAT=seat0
    HOME=/home/li
    SHLVL=2
    GNOME_DESKTOP_SESSION_ID=this-is-deprecated
    XDG_SESSION_DESKTOP=gnome-classic
    LOGNAME=li
    XDG_DATA_DIRS=/home/li/.local/share/flatpak/exports/share/:/var/lib/flatpak/exports/share/:/usr/local/share/:/usr/share/
    DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-uwrzkuJLBV,guid=3f90f6b70bfb6e9c73faf7a862fcf3e1
    LESSOPEN=||/usr/bin/lesspipe.sh %s
    WINDOWPATH=1
    XDG_RUNTIME_DIR=/run/user/1000
    DISPLAY=:0
    XDG_CURRENT_DESKTOP=GNOME-Classic:GNOME
    COLORTERM=truecolor
    XAUTHORITY=/run/gdm/auth-for-li-6t7NT7/database
    _=/usr/bin/env
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45

    2.3.2 如何定义变量和给变量赋值

    在Shell中,当你第一次使用某变量名时,实际上就定义了这个变量。在Shell中创建和设置变量时很简单的,其语法如下:

    varName=varValue
    
    • 1

    我们可以看到可以使用赋值号"=“给变量赋值。输入的次序是:变量名、赋值操作符和赋予的值,varName即是变量名,varValue是赋予varName的值。如果没有给出varValue,则变量varName被赋予一个空字符串。
    在赋值操作符”="的周围,不要有任何空格,如果有会报command not found的错误:
    下列是错误示例:

    varName = varValue
    varName =varValue
    varName= varValue
    
    • 1
    • 2
    • 3

    可以把任意字符集合赋值给一个变量。如下示例:

    $ username=yantaol
    或者
    $ username="yantaol"
    # 中间有空格的字符串赋值时必须使用"",将字符串引起来。不使用双引号""无法创建变量。
    [li@hadoop102 ~]$ var="li jie"
    [li@hadoop102 ~]$ echo $var
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    将一个数字赋值给变量:

    $ var=1
    
    • 1

    需要注意的是Shell的默认赋值时字符串赋值,如下示例:

    $ var=$var+1
    $ echo $var
    $ 1+1
    
    • 1
    • 2
    • 3

    得到的结果是一个"1+1"的串,而不是计算出来的"2"。在Bash中,如果要将算术表达式的数值赋值给一个变量,可以使用let命令,如下实例:

    $ let var=2+1
    $ echo $var
    3
    
    • 1
    • 2
    • 3

    将一个变量的值直接赋值给另一个变量,示例如下:

    [root@hadoop100 ~]# a=3
    [root@hadoop100 ~]# b=$a
    [root@hadoop100 ~]# echo $b
    3
    
    • 1
    • 2
    • 3
    • 4

    将命令的执行结果赋值给变量,可以使用$(…)。示例如下:

    [li@hadoop102 ~]$ var=$(pwd)
    [li@hadoop102 ~]$ echo $var
    /home/li
    
    • 1
    • 2
    • 3

    将Bash的内置命令read读入的内容赋值给变量:

    [li@hadoop102 ~]$ echo -n "Enter var:"; read var
    Enter var:123
    [li@hadoop102 ~]$ echo $var
    123
    [li@hadoop102 ~]$ read -p "Enter var:" var
    Enter var:123
    [li@hadoop102 ~]$ echo $var
    123
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    echo -n “Enter var:” 语句是打印内容"Enter var:“并且不换行,紧接着从标准输入读入内容,输入值"123"后回车,read命令将读入的内容赋值给var,使用echo可以看到var的值是"123”。

    2.3.3 变量命名规则

    变量名必须以字母或下划线字符"_"开头,后面跟字符、数字或下划线字符,第一个字符不能为数字。不要使用?、*和其他特殊字符命名变量。
    有效的Shell变量名示例如下:

    USERNAME
    LD_LIBRARY_PATH
    _VAR
    var1
    
    • 1
    • 2
    • 3
    • 4

    如下是无效的变量名:

    ?var=123
    user*name=yantao
    
    • 1
    • 2

    变量名是大小写敏感的,如下几个变量是不同的变量:

    bash-4.2$ VAR=3
    bash-4.2$ var=123
    bash-4.2$ Var=1
    bash-4.2$ vAr=2
    bash-4.2$ vaR=3
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2.3.4 使用echo和printf打印变量的值

    可以使用echo命令显示变量的值,还有一种显示变量的方法,就是printf命令,如下所示:

    [li@hadoop102 ~]$ printf "%s\n" $var
    123
    [li@hadoop102 ~]$ printf "%s" $var
    123[li@hadoop102 ~]$
    
    • 1
    • 2
    • 3
    • 4

    printf命令提供了一个类似于printf()系统接口(C函数)的打印格式化文本的方法。它作为echo命令的替代,提供了更多的特性。printf命令的语法格式如下:

    printf  
    
    • 1

    printf命令就是根据指定的格式打印的内容。文本格式在中指定,紧接着是需要格式化的所有参数。
    示例如下:

    [li@hadoop102 ~]$ printf "FirstName: %s\nLastName: %s\n" "FIRSTNAME" "LASTNAME"
    FirstName: FIRSTNAME
    LastName: LASTNAME
    
    • 1
    • 2
    • 3

    其中"FirstName: %s\nLastName: %s\n" 是格式规范,而后面的两个变量则作为参数传入。格式用字符串中的%s是指示打印参数的格式类型的分类符,这些分类符有不同的名字,如表:

    分类符描述
    %b打印相关参数并解释其中带有反斜杠"\"的特殊字符
    %q以Shell引用的格式打印相关参数,使其可以在标准输入中重用
    %d以带符号十进制数的格式打印相关参数
    %i与%d相同
    %o以无符号八进制数的格式打印相关参数
    %u以无符号十进制数的格式打印相关参数
    %x以无符号小写十六进制数的格式打印相关参数
    %X与%x相同,只是十六进制数为大写
    %f以浮点数的格式解析并打印相关参数
    %e以双精度浮点数土e的格式打印相关参数
    %E与%e相同,只是用大写字母E
    %g以%f或%e的格式打印相关参数
    %G以%f或%E的格式打印相关参数
    %c以字符的格式打印相关参数,并且只打印参数中的第一个字符
    %s以字符串的格式打印相关参数
    %n指定打印的字符个数
    %%表示打印一个字符"%"

    在printf命令的格式用字符串中还可以使用一些转义字符,如表:

    转义符描述
    \"打印双引号
    \NNN用八进制的值表示一个ASCII字符,例如\101,即65,表示字符"A"
    \\打印一个反斜杠"\"
    \a发出警告音
    \b删除前一个字符
    \f换页符,在某些实现中会清屏,有些会换行
    \n换行
    \r从行头开始,和换行不一样,仍在本行
    \tTab键
    \v竖直tab,和\f相似,不同机器显示有所不同,通常会引起换行VERTICAL TAB or CTRL-K
    \xHH用十六进制的值表示一个ACSII字符,例如:/x41,即65,表示字符"A"

    接下来通过一些实例,了解以下如何使用printf命令格式化打印变量的值。

    [root@hadoop100 ~]# var=shell
    [root@hadoop100 ~]# printf "%s\n" $var
    shell
    
    [root@hadoop100 ~]# printf "%1s\n" $var # 如果指定的长度小于参数实际的长度,则打印完整的字符串
    shell
    
    [root@hadoop100 ~]# printf "%1.1s\n" $var # 原点符右边的数字指示打印参数中字符的个数
    s
    
    [root@hadoop100 ~]# printf "%1.2s\n" $var
    sh
    
    [root@hadoop100 ~]# printf "%2.6s\n" $var
    shell
    
    [root@hadoop100 ~]# printf "%10.4s\n" $var # 如果指定打印的字符串长度超过输出的实际长度,则左边用空格补全
          shel
    
    [root@hadoop100 ~]# printf "%c\n" $var
    s
    
    
    [root@hadoop100 ~]# printf "%d\n" $var
    -bash: printf: shell: 无效数字
    
    [root@hadoop100 ~]# var=100
    [root@hadoop100 ~]# printf "%d\n" $var
    100
    
    [root@hadoop100 ~]# printf "%s%%\n" $var
    100%
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    与printf命令不同,echo命令没有提供格式化选项,因此echo命令也比printf命令更简单易用,当你知道要显示的变量的内容不会引起问题时,echo命令是一个很好的显示简单输出的命令。
    echo命令也提供转义字符的功能,可以使用的转义字符与printf命令中的基本相同,但需使用“-e”选项激活转义字符功能。下列我们通过一些实例来了解如何使用echo命令打印变量的值。

    [root@hadoop100 ~]# var=10
    [root@hadoop100 ~]# echo "The number is $var"
    The number is 10
    
    [root@hadoop100 ~]# echo -e "UserName:$USER\nHome directory:$HOME\n"
    UserName:root
    Home directory:/root
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    有时需要使用${}避免一些歧义。例如:

    [root@hadoop100 ~]# echo "The log file is $LOGDIR messages"
    The log file is /var/log/ messages
    
    
    [root@hadoop100 ~]# LOGDIR="/var/log/"
    [root@hadoop100 ~]# echo "The log file is $LOGDIRmessages"
    The log file is
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    Bash将尝试查找一个叫做LOGDIRmessages的变量,而不是$LOGDIR。为了避免这种歧义,在这里我们可以就需要使用${}语法,如下所示:

    [root@hadoop100 ~]# echo "The log file is ${LOGDIR}messages"
    The log file is /var/log/messages
    
    • 1
    • 2

    2.3.5 变量的引用

    当引用一个变量时,通常最好是双引号将变量括起来。例如:“$variable”。这样可以防止被引用的变量值中的特殊字符(除:$、'、\)被解释为其他错误含义。
    使用双引号可以防止变量值中由多个单词组成的字符串分离。一个用双引号括起来的变量使它自身变成一个单一词组,即使它的值中包含空格。用一个实例来了解以下双引号在引用变量中的作用。如下示例:

    LIST="one two three"
    for var in $LIST # 将变量LIST的值分成了3个参数传递给for循环
    do
      echo "$var"
    done
    
    结果:
    one
    two
    three
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    LIST="one two three"
    for var in "$LIST" # 将变量LIST的值作为一个整体传递给for循环
    do
      echo "$var"
    done
    
    结果:
    one two three
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    注意:只有在变量的值中包含空格或要保留其中的空格时,将变量用双引号括起来才是必要的。
    单引号的操作类似于双引号,但是它不允许引用变量,因为在单引号中字符"$"的特殊含义将会失效。每个特殊的字符,除了字符’,都将按字面含义解释。

    2.3.6 export语句的使用

    用户登录系统后,系统将启动一个登录Shell。在这个Shell中,可以声明一些变量,也可以创建并运行Shell脚本程序。运行Shell脚本时,系统将创建一个子Shell,当此Shell脚本运行完毕时,这个子Shell将终止,环境将返回到执行该脚本运行之前的Shell。默认情况下,所有用户定义的变量只在当前Shell内有效,它们不能被后续的Shell引用,要使某个变量可以被子Shell引用,可以使用export命令将变量进行输出。
    Bash的内置命令export会将指定给它的变量或函数自动输出到后续命令的执行环境。export命令的语法如下所示:

    export [-fnp] [变量或函数名称] = [变量设置值]
    
    • 1
    • -f:表示export一个函数;
    • -n:表示将export属性从指定变量或函数上移位;
    • -p:打印当前Shell所有输出的变量,与单独执行export命令结果相同。

    示例:创建一个变量JAVE_HOME,然后给它赋予一个值:“/usr/local/jdk”,代码如下:
    创建JAVA_HOME变量,使用echo命令显示变量的值:

    [root@hadoop100 ~]# JAVA_HOME=/usr/local/jdk
    [root@hadoop100 ~]# echo $JAVA_HOME
    /usr/local/jdk
    
    • 1
    • 2
    • 3

    再运行一个新的子Shell:

    bash
    
    • 1

    再使用echo命令显示变量JAVA_HOME的值:

    echo $JAVA_HOME
    
    • 1

    将会得到一个空行,因为变量JAVA_HOME没有被输出到新的子Shell。
    退出子Shell:

    exit
    
    • 1

    接下来使用export命令,将变量JAVA_HOME输出后续命令的执行环境:

    export $JAVA_HOME
    
    • 1

    现在运行一个新的子Shell,再使用echo命令显示变量JAVA_HOME的值:

    [root@hadoop100 ~]# bash
    [root@hadoop100 ~]# echo $$
    2809
    [root@hadoop100 ~]# echo $JAVA_HOME
    /usr/local/jdk
    
    • 1
    • 2
    • 3
    • 4
    • 5

    再运行一个新的子Shell,变量JAVA_HOME仍然有效。
    注意:系统变量会自动输出到后续命令的执行环境。

    2.3.7 如何删除变量

    Bash下使用unset命令来删除相应的变量或函数。unset命令会把变量从当前Shell和后续命令的环境中删除。其命令的语法如下:

    unset [-fv] [变量或函数名称]
    
    • 1
    • -f:表示删除一个已定义的函数;
    • -v:表示删除一个变量。

    使用unset命令:

    [root@hadoop100 ~]# export JAVA_HOME=/usr/local/jkd
    [root@hadoop100 ~]# unset JAVA_HOME
    [root@hadoop100 ~]# echo $JAVA_HOME
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5

    注意:使用unset命令不能删除一个只读的变量,否则将会出现报错。

    2.3.8 如何检查变量是否存在

    可以使用如下语法,来检查一个变量是否存在:

    ${varName?  Error: The variable is not defind}
    
    • 1

    上述语句的含义是如果变量varName已定义且不为空,则此语句就相当于$varName;如果变量varName的值是空,则此语句的值也是空;但如果varName是未定义的,则此语句将返回一个错误,并显示问号"?"定义的错误信息:“Error:The variable is not defind”。或者,使用下面这句:

    ${varName:?  Error: The variable is not defind}
    
    • 1

    示例:

    JAVA_HOME=/usr/local/jdk
    echo ${JAVA_HOME? ERROR:The variable is not defined}
    
    • 1
    • 2
    [root@hadoop100 ~]# JAVA=
    [root@hadoop100 ~]# echo ${JAVA? error:the variable is not defined}
    
    [root@hadoop100 ~]# echo ${JAVA:? error:the variable is not defined}
    -bash: JAVA:  error:the variable is not defined
    # 如果变量为空,此语句也将返回一个错误
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    2.4 Shell环境进阶

    2.4.1 回调命令历史

    Bash将命令历史保存在缓冲区或是默认文件~/.bash_history中。历史命令缓冲区中可以保存很多命令,其 保存命令的多少有环境变量HISTSIZE定义。
    可以使用history命令显示你在命令行提示符下输入的命令列表,如下所示:

    history
    
        1  vim /etc/sysconfig/network-scripts/ifcfg-ens33
        2  ifconfig
        3  service nerwork restarts
        4  service network restart
        5  ifconfig
        6  ping 192.168.124.4
        7  service network restart
        8  ifconfig
        9  vim etc/sysconfig/network-scripts/ifcfg-ens33
       10  vim /etc/sysconfig/network-scripts/ifcfg-ens33
       11  vim /etc/hostname
       12  hostnamectl
       13  vim /etc/sysconfig/network-scripts/ifcfg-ens33
       14  vim /etc/hosts
       15  quit
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    在Shell命令行提示符下,可以简单地输入!!,来重复执行上一条执行过的命令,还可以回调最近一次执行的以指定字符开头的命令,如:“!up”。甚至可以使用由history命令列出来的列表的行号来重新调用相应的历史命令,如:“!15”。

    2.4.2 Shell中的扩展

    Shell中扩展的方式 有8种,分别是(按扩展的先后顺序排序):大括号扩展、波浪号扩展、参数和变量扩展、命令替换、算术扩展、进程替换、单词拆分和文件名扩展。本小节主要介绍大括号扩展、波浪号扩展、命令替换和文件名扩展。
    大括号扩展是一种能够生成任意字符串的机制。进行大括号扩展的模式在形式上有一个可选的前缀,其后是一组包含在大括号内的用逗号分隔的字符串或是序列表达式,最后是一个可选的后缀。例如:

    $ echo a{b,c,d}e
    abe ace ade
    
    $ echo {a..z} # 按字母表顺序显示a~z的字母
    a b c d e f g h i j k l m n o p q r s t u v w x y z
    
    $ echo {0..10}
    0 1 2 3 4 5 6 7 8 9 10
    
    $ echo {1..3}{a..c}
    1a 1b 1c 2a 2b 2c 3a 3b 3c
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    大括号扩展也可以是嵌套的。每个扩展字符串的结果是不排序的,依然按照从左到右的顺序依次扩展。例如:

    $ echo a{{b,c,d}a,{e,f,g}b,h}i
    abai acai adai aebi afbi agbi ahi
    
    $ echo {a,b{1..3},c}
    a b1 b2 b3 c
    
    • 1
    • 2
    • 3
    • 4
    • 5

    大括号扩展和许多命令配合使用,可以使你的命令更简化,比如想在主目录下创建三个目录,可以用类似如下语句:

    mkdir ~/{dir1,dir2,dir3}
    
    • 1

    波浪号扩展可用来指代你自己的主目录,或其他人的主目录。例如:

    cd ~
    cd ~fred # 进入用户fred目录
    
    • 1
    • 2

    命令替换是用命令的输出替换命令本身,命令替换有如下两种形式:

    $ (COMMAND)
    
    • 1

    Bash进行这个扩展时,先执行命令,然后用命令的标准输出结果取代命令替换,命令的标准输出结果中最后面的换行符会被删除。如下所示:

    [root@hadoop100 ~]# echo $(uptime)
    09:14:11 up 6 min, 1 user, load average: 0.01, 0.03, 0.02
    
    
    • 1
    • 2
    • 3

    命令替换可以嵌套。使用反引号形式“``”进行嵌套时,里面的反引号需要用反斜杠""转义。
    如果Bash中没有设置-f选项,就会支持文件名扩展。Bash支持以下三种通配符来实现文件名扩展:

    • *:匹配任何字符串,包括空字符串。
    • ?:匹配任意单个字符。
    • […]:匹配方括号内的任意字符。

    比如,显示/etc目录下的所有配置文件:

    ls /etc/*.conf
    ls /etc/[ab]*.conf
    ls image?.jpg
    
    • 1
    • 2
    • 3

    2.4.3 创建和使用别名

    在Linux系统环境中,我们通常需要使用命令行处理一些任务,并且会很频繁地使用某些命令语句。为了节省时间,我们可以在文件~/.bashrc中为这些命令语句创建一些别名。
    注意:一旦修改了~/.bashrc文件,必须重新登录Shell后,新的设置才会生效。
    Bash的内置命令alias用于创建一个别名,创建别名的语法如下:

    alias name='command'
    
    • 1
    • name:用户定义的用于别名的任意简短的名字。
    • command:任意Linux命令。

    如下实例:

    alias ll='ls -l'
    
    
    • 1
    • 2

    注意:在命令行执行这个命令时,会创建一个临时的别名。就是说,这个别名只在当前Shell中有效

    2.4.4 修改Bash提示符

    环境变量PS1,设置此变量即可用于定制自己的Bash提示符。显示当前提示符的设置,代码如下:

    [root@hadoop100 ~]# echo $PS1
    [\u@\h \W]\$
    
    
    • 1
    • 2
    • 3

    在比例中,变量PS1的值显示了如下信息:

    提示符说明
    \u当前用户的用户名
    \h主机名
    \w当前工作目录的全路径
    \n新的一行
    \$如果当前用户UID是0,则显示符号"#“,否则显示”$"

    2.5 小结

    下面我们总结一下本章所学的主要知识:
    ● Bash是大多数Linux系统的默认Shell,它与原来的Unix sh shell向后兼容,并且融合了一些有用的Korn Shell和C Shell的特性。
    ● 用户登录时,登录Shell调用的初始化文件和脚本的次序依次是:/etc/profile、/etc/profile.d目录下的脚本、$HOME/.bash_profile、$HOME/.bashrc、/etc/bashrc。
    ● 一旦修改了~/.bashrc文件,你必须重新登录Shell后,新的设置才会生效。
    ● 当登录Shell退出时,如果$HOEM/.bash_logout脚本存在的话,bash会读取并执行此脚本的内容。
    ● Shell中有两种变量的类型:系统变量(环境变量)和用户自定义的变量(本地变量或Shell变量)。
    ● Bash中定义变量和赋值的方法:varName=varValue,在赋值操作符“=”的周围,不要有任何空格。
    ● Bash变量名必须以字母或下划线字符“_”开头,后面跟字母数字或下划线字符,第一个字符不能为数字。
    ● 当引用一个变量时,通常最好是用双引号将变量名括起来,这样可以防止被引用的变量值中的特殊字符(除:$, `和\)被解释为其他错误含义。
    ● Bash的内置命令export会将指定给它的变量或函数自动输出到后续命令的执行环境。
    ● Bash中使用unset命令删除相应的变量或函数。
    ● 使用history命令可以显示你在命令行提示符下输入的命令列表。
    ● Shell中扩展的方式有八种,它们分别是(按扩展的先后顺序排序):大括号扩展、波浪号扩展、参数和变量扩展、命令替换、算术扩展、进程替换、单词拆分和文件名扩展。
    ● Bash的内置命令alias用于创建一个别名。
    ● 如果你想每次登录时自动设置你的Shell提示符,你需要将环境变量PS1放在你的~/.bashrc文件中,并使用export命令将其输出到其它子命令。
    ● Bash的内置命令set和shopt可以用于设置Shell选项。

  • 相关阅读:
    Delphi编程中的按键模拟及应用——使用SendInput函数实现按键模拟
    Roson的Qt之旅#109 QML ListView的成员属性介绍
    vue3 - 项目集成vue-i18n国际化和Element Plus 国际化
    代码随想录之单调栈|739. 每日温度,496.下一个更大元素 I
    MySQL——连接查询
    CocosCreator 面试题(五)TS有什么优缺点?为什么要用TS?
    10 分钟了解 Pulsar:针对 Kafka 用户的指南
    深圳SMT贴片行业MES系统解决方案~MES系统服务商~先达智控
    《学术小白学习之路11》DTM主题动态模型原理与基础构建
    判断二叉树是否为满二叉树
  • 原文地址:https://blog.csdn.net/shield911/article/details/126907109