所有的编程语言都利用变量来存放数据,以备随后使用或修改。和编译型语言不同,大多数脚本语言不要求在创建变量之前声明其类型。用到什么类型就是什么类型。在变量名前面加上一个$符号就可以访问到变量的值。shell定义了一些变量,用于保存用到的配置信息,比如可用的打印机、搜索路径等。这些变量叫作环境变量。

1.3.1 预备知识

变量名由一系列字母、数字和下划线组成,其中不包含空白字符。常用的惯例是在脚本中使用大写字母命名环境变量,使用驼峰命名法或小写字母命名其他变量。

所有的应用程序和脚本都可以访问环境变量。可以使用envprintenv命令查看当前shell
中所定义的全部环境变量:

  1. [root@dev workspace]# env
  2. WORKSPACE=/root/workspace
  3. PWD=/root/workspace
  4. HOME=/root
  5. GOROOT=/root/go/go1.17.6
  6. NAME=MiHome
  7. GOPRIVATE=
  8. MAIL=/var/spool/mail/root
  9. SHELL=/bin/bash
  10. # …… 其他行

要查看其他进程的环境变量,可以使用如下命令:

  1. cat /proc/$PID/environ
  2. [root@dev workspace]# ls /proc
  3. 1 buddyinfo cpuinfo execdomains irq kpagecgroup meminfo pagetypeinfo stat tty
  4. 28 bus crypto filesystems kallsyms kpagecount misc partitions swaps uptime
  5. 7 cgroups devices fs kcore kpageflags modules sched_debug sys version
  6. 8 cmdline diskstats interrupts keys loadavg mounts schedstat sysvipc vmallocinfo
  7. 9 config.gz dma iomem key-users locks mtrr self thread-self vmstat
  8. acpi consoles driver ioports kmsg mdstat net softirqs timer_list zoneinfo
  9. [root@dev workspace]# cat /proc/cpuinfo

image.png
其中,PID是相关进程的进程IDPID是一个整数)。

设有一个叫作gedit的应用程序正在运行。我们可以使用pgrep命令获得gedit的进程ID:

  1. $ pgrep gedit
  2. 12501

那么,你就可以执行以下命令来查看与该进程相关的环境变量:

  1. $ cat /proc/12501/environ
  2. GDM_KEYBOARD_LAYOUT=usGNOME_KEYRING_PID=1560USER=slynuxHOME=/home/slynux

注意,实际输出的环境变量远不止这些,只是考虑到页面篇幅的限制,这里删除了不少内容。

特殊文件/proc/PID/environ是一个包含环境变量以及对应变量值的列表。每一个变量以name=value的形式来描述,彼此之间由null字符(\0)分隔。形式上确实不太易读。

要想生成一份易读的报表,可以将cat命令的输出通过管道传给tr,将其中的\0替换成\n

  1. $ cat /proc/12501/environ | tr '\0' '\n'

1.3.2 实战演练

可以使用等号操作符为变量赋值:

  1. varName=value

varName是变量名,value是赋给变量的值。如果value不包含任何空白字符(例如空格),那么就不需要将其放入引号中,否则必须使用单引号或双引号。

注意var = value不同于var=value。把var=value写成var = value是一个常见的错误。两边没有空格的等号是赋值操作符,加上空格的等号表示的是等量关系测试。

在变量名之前加上美元符号($)就可以访问变量的内容。

  1. [root@dev workspace]# var="value" #将"value"赋给变量var
  2. [root@dev workspace]# echo $var
  3. value
  4. [root@dev workspace]#

也可以这样写:

  1. [root@dev workspace]# var="value" #将"value"赋给变量var
  2. [root@dev workspace]# echo ${var}
  3. value
  4. [root@dev workspace]#

输出如下:

  1. value

我们可以在printfecho或其他命令的双引号中引用变量值:

  1. #!/bin/bash
  2. #文件名:variables.sh
  3. fruit=apple
  4. count=5
  5. echo "We have $count ${fruit}(s)"
  1. #!/bin/bash
  2. [root@dev workspace]# vi variables.sh
  3. [root@dev workspace]# chmod +x variables.sh
  4. [root@dev workspace]# ./variables.sh
  5. We have 5 apple(s)
  6. [root@dev workspace]#

输出如下:

  1. We have 5 apple(s)

因为shell使用空白字符来分隔单词,所以我们需要加上一对花括号来告诉shell这里的变量名是fruit,而不是fruit(s)

环境变量是从父进程中继承而来的变量。例如环境变量HTTP_PROXY,它定义了Internet连接应该使用哪个代理服务器。

该环境变量通常被设置成:

  1. HTTP_PROXY=192.168.1.23:3128
  2. export HTTP_PROXY

export命令声明了将由子进程所继承的一个或多个变量。这些变量被导出后,当前shell脚本所执行的任何应用程序都会获得这个变量。shell创建并用到了很多标准环境变量,我们也可以导出自己的环境变量。

例如,PATH变量列出了一系列可供shell搜索特定应用程序的目录。一个典型的PATH变量包含如下内容:

  1. [root@dev workspace]# echo $PATH
  2. /root/go/go1.17.6/bin:/root/workspace/golang/bin:/usr/local/libexec/git-core:/root/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/usr/lib/wsl/lib

各目录路径之间以:分隔。$PATH通常定义在/etc/environment/etc/profile~/.bashrc中。

如果需要在PATH中添加一条新路径,可以使用如下命令:

  1. export PATH="$PATH:/home/user/bin"

也可以使用

  1. PATH="$PATH:/home/user/bin"
  2. export PATH
  3. echo $PATH
  4. /home/slynux/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/home/user/bin

这样,我们就将/home/user/bin添加到了PATH中。

另外还有一些众所周知的环境变量:HOMEPWDUSERUIDSHELL等。

使用单引号时,变量不会被扩展(expand),仍依照原样显示。这意味着 $echo '$var'会显示$var

但如果变量$var已经定义过,那么$ echo "$var"会显示出该变量的值;如果没有定义过,则什么都不显示。

image.png

1.3.3 补充内容

shell还有很多内建特性。下面就是其中一些。

获得字符串的长度

可以用下面的方法获得变量值的长度:

  1. [root@dev workspace]# var="value" #将"value"赋给变量var
  2. [root@dev workspace]# echo length=${#var}
  3. length=5
  4. [root@dev workspace]#

考虑这个例子:

  1. [root@dev workspace]# var=12345678901234567890;echo ${#var}
  2. 20
  3. [root@dev workspace]#

length就是字符串所包含的字符数。

识别当前所使用的 shell

可以通过环境变量SHELL获知当前使用的是哪种shell

  1. [root@dev workspace]# echo $SHELL
  2. /bin/bash

也可以用

  1. [root@dev workspace]# echo $0
  2. -bash

检查是否为超级用户

环境变量UID中保存的是用户ID。它可以用于检查当前脚本是以root用户还是以普通用户的身份运行的。例如:

  1. if [ $UID -ne 0 ]
  2. then
  3. echo "Non root user. Please run as root."
  4. else
  5. echo "Root user"
  6. fi

image.png

注意,[实际上是一个命令,必须将其与剩余的字符串用空格隔开。上面的脚本也可以写成:

  1. if test $UID -ne 0:1
  2. then
  3. echo "Non root user. Please run as root."
  4. else
  5. echo "Root user"
  6. fi

image.png
root用户的UID0

修改 Bash 的提示字符串(username@hostname:~$)

当我们打开终端或是运行shell时,会看到类似于user@hostname:/home/$的提示字符串。
不同的GNU/Linux发布版中的提示字符串及颜色各不相同。我们可以利用PS1环境变量来定义主
提示字符串。默认的提示字符串是在文件~/.bashrc中的某一行设置的。

  • 查看设置变量PS1的那一行:

    1. [root@dev workspace]# cat ~/.bashrc | grep PS1
    2. export PS1='[\u@dev \W]\$ ' # 默认的 PS1 设置会展示全部的路径,为了防止过长,这里只展示:"用户名@dev 最后的目录名"
    3. [root@dev workspace]#
  • 如果要修改提示字符串,可以输入:

    1. lynux@localhost: ~$ PS1="PROMPT>" #提示字符串已经改变
    2. PROMPT> Type commands here.
  • 我们可以利用类似于\e[1;31的特定转义序列来设置彩色的提示字符串(参考 1.2 节的内容)。

还有一些特殊的字符可以扩展成系统参数。例如:\u可以扩展为用户名,\h可以扩展为主机名,而\w可以扩展为当前工作目录。