Linux 下 shell 中的变量

本文深入探讨了Shell变量的概念,包括变量的定义、使用、修改及规则,特别关注环境变量的作用与设置。同时,文章提供了如何查看和操作变量的具体方法,以及变量在不同场景下的应用实例。

之前我们说 shell 是沟通内核和用户的桥梁,能够实现很多功能。每个用户(包括系统用户)登陆时都会获得一个 shell。在 shell 中为了方便使用也会定义很多变量,这些变量就是常说的环境变量。

什么是变量

和编程语言中的变量定义类似,变量可以用来表示或者替换一些数据和设置。

变量的使用和设置

查看特定变量 echo

使用已经定义好的变量需要在变量名前加上 $,比如使用 echo 命令可以看到变量的内容:

wood@ubuntu:~$ echo $PATH
/opt/Anaconda3/bin:/home/wood/bin:/home/wood/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
wood@ubuntu:~$ echo ${PATH}
/opt/Anaconda3/bin:/home/wood/bin:/home/wood/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin

可以通过上面所示的两种方法对变量进行引用,虽然上面两种方法都是可行的,但是为了适应其它平台的写法(VS Code等)建议写成 ${PATH} 的形式。

定义和修改变量 =

和其它编程语言类似,变量的定义和修改都是通过 = 来实现的:

wood@ubuntu:~$ echo ${var}

wood@ubuntu:~$ var = var_value
No command 'var' found, but there are 21 similar ones
var: command not found
wood@ubuntu:~$ var=var_value
wood@ubuntu:~$ echo ${var}
var_value
wood@ubuntu:~$ ^C
wood@ubuntu:~$ var="var_value"
wood@ubuntu:~$ echo ${var}
var_value

从上边的结果可以看出:

  • 在没有定义相关变量之前,利用 echo 命令查看变量会显示为空
  • 变量名和变量值之间只有一个 =,没有多余的空格
  • “var_value” 和 var_value 赋值后的结果是一样的

变量的设置规则

  • 变量名和变量值之间只以一个 = 连接
  • 等号两边不能接空格
  • 变量名称由英文字母和数字构成,但开头字符不能是数字
  • 变量内容若有空格可以使用双引号和单引号将变量内容结合,但
    • 双引号内的特殊字符 $ 保有原有的特性
    • 单引号内的特殊字符则为一般字符(纯文本)
wood@ubuntu:~$ var1="var value is ${var}"
wood@ubuntu:~$ echo ${var1}
var value is var_value
wood@ubuntu:~$ var2='var value is ${var}'
wood@ubuntu:~$ echo ${var2}
var value is ${var}
  • 可以使用转义字符\将特殊符号(回车,$,\,whitespace等)变为一般字符
wood@ubuntu:~$ var3=VS Code
No command 'Code' found, did you mean:
 Command 'node' from package 'nodejs-legacy' (universe)
 Command 'ode' from package 'plotutils' (universe)
Code: command not found
wood@ubuntu:~$ var3=VS\ Code
wood@ubuntu:~$ echo ${var3}
VS Code
  • 单引号和双引号需要成对使用,以先检测的括号为准
wood@ubuntu:~$ var4="VS's Code"
wood@ubuntu:~$ echo ${var4}
VS's Code
wood@ubuntu:~$ var4='VS's Code'
> 
  • 在一串命令的执行过程中,如果还会使用到其它额外的命令所提供的信息时,可以使用 `command` 或者 $(command) 的形式。
wood@ubuntu:~$ var5=$(echo ${var4})
wood@ubuntu:~$ echo ${var5}
VS's Code
  • 如果该变量为扩增变量内容时,则要用 “$var“ 或者 ${var} 来进行累加
wood@ubuntu:~$ var6=${var5}\ Code
wood@ubuntu:~$ echo ${var6}
VS's Code Code
  • 如果该变量需要在其它子程序中使用,则需要使用export命令使变量变为环境变量
  • 通常大写字符为系统默认变量,用户自定义变量可以随便,但是为了方便使用,最好有自己的风格
  • 取消变量则需要使用unset命令
wood@ubuntu:~$ echo ${var1} ${var2} ${var3} ${var4} ${var5} ${var6}
var value is var_value var value is ${var} VS Code VS's Code VS's Code VS's Code Code
wood@ubuntu:~$ unset var1 var2 var3 var4 var5 var6
wood@ubuntu:~$ echo ${var1} ${var2} ${var3} ${var4} ${var5} ${var6}

环境变量

什么是环境变量

之前我们提到变量可以用来表示或者替换一些数据和设置。但是变量的影响范围也是不同的,之前提到的变量在该进程结束也就是 shell 登出的时候就会被消除,而环境变量在不修改的情况下则并不会消失。比如我们在终端中输入 python 会显示 python 的版本信息并进入到对应的 python 环境中。此时在终端中输入的 python 就存在于环境变量中。

wood@ubuntu:~$ python
Python 3.6.5 |Anaconda, Inc.| (default, Apr 29 2018, 16:14:56) 
[GCC 7.2.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 

查看环境变量 env

wood@ubuntu:~$ env
XDG_VTNR=7
XDG_SESSION_ID=c2
CLUTTER_IM_MODULE=ibus
XDG_GREETER_DATA_DIR=/var/lib/lightdm-data/wood
GPG_AGENT_INFO=/home/wood/.gnupg/S.gpg-agent:0:1
SHELL=/bin/bash
...

上面显示的是我的计算机中的部分环境变量。

常见的环境变量

HOME

表示用户的根目录。

SHELL

表示目前环境中使用的 shell 程序。

HISTSIZE

表示记录的历史命令条数。

MAIL

表示使用 mail 命令收信时,系统会去读取的邮箱文件。

PATH

表示执行文件查找的路径,目录与目录之间用冒号分隔。目录的顺序会影响查找的结果。

LANG

表示语系数据。

RANDOM

表示随机数变量。

查看所有变量 set

使用命令 set 可以列出所有的变量,包括环境变量和自定义变量:

wood@ubuntu:~$ set
BASH=/bin/bash
BASHOPTS=checkwinsize:cmdhist:complete_fullquote:expand_aliases:extglob:extquote:force_fignore:histappend:interactive_comments:progcomp:promptvars:sourcepath
BASH_ALIASES=()
BASH_ARGC=()
BASH_ARGV=()
BASH_CMDS=()
BASH_COMPLETION_COMPAT_DIR=/etc/bash_completion.d
BASH_LINENO=()
BASH_SOURCE=()
...

当然下方还存在着很多变量,尤其是在显示的最后会出现一堆类似代码的东西,可能是于当前 shell 相关的变量吧。

比较重要的变量

在上边显示的变量中,有几个变量见得会比较多:

PS1

这里的 PS1 表示的是命令提示字符,在本计算机上显示为:

wood@ubuntu:~$

除此之外还有别的设置,分别为:

\d

显示完整的(星期,月,日)的日期格式

\H完整的主机名
\h仅取主机名在第一个小数点之前的名字
\t显示时间,24小时格式的(HH:MM:SS)
\T显示时间,12小时格式的(HH:MM:SS)
\A显示时间,24小时格式的(HH:MM)
\@显示时间,12小时格式的(am/pm)格式
\u目前用户的账号名称
\vbash 的版本信息
\w

完整的工作目录名称,由根目录写起的目录名称,但根目录会以~替换

\W利用 basename 函数取得工作目录名称,只会列出最后一个目录名
\#

执行的第几个命令

\$提示字符,root为#,否则为$

$

该符号不止可以用来查看变量的值,并且该符号本身就是一个变量,表示目前这个 shell 的进程号,也就是 PID。

?

该符号在 Linux 中也表示一个特殊的变量,就是上一个执行的命令所返回的值。

一般情况下,命令执行后都会返回一个执行后的代码,命令执行成功则返回0,执行过程发生错误则返回非 0 值。

OSTYPE,HOSTTYPE,MACHTYPE

这几个变量是与硬件相关的,分别表示操作系统类型,主机硬件和内核等级。

export 

之前我们提到过可以使用 export 命令将自定义变量转化为环境变量,这是因为自定义的变量只存在于当前进程当中。

以 bash 为例,在当前 bash 中自定义的变量在 bash 退出并重新登录后是不存在的,这也从侧面说明了自定义变量是绑定到进程当中的。

但在当前 bash 中重新打开一个进程 bash 后,这个进程可以称为是一个子进程,该子进程会进程父进程的自定义变量,但是父进程却不能够调用子进程的自定义变量。

因此 export 就是为了将自定义变量变得更加通用的命令,export 后不跟参数时,会显示所有的环境变量:

wood@ubuntu:~$ export
declare -x CLUTTER_IM_MODULE="ibus"
declare -x COMPIZ_CONFIG_PROFILE="ubuntu"
declare -x DBUS_SESSION_BUS_ADDRESS="unix:abstract=/tmp/dbus-taYCOVhDo0"
declare -x DEFAULTS_PATH="/usr/share/gconf/ubuntu.default.path"
...

变量声明和读取

从上面的内容我们知道,shell 的变量可以类比编程语言中的变量,在编程语言比如 C 语言中,我么能够使用函数 scanf 来读取键盘输入为定义的变量赋值,其实在 shell 中也是可以的。

read

描述:

读取来自键盘输入的变量。

语法:

read [-pt] var

选项和参数:

-p:后接提示字符

-t:表示要等待的时长,超时则跳过

wood@ubuntu:~$ read var
apple
wood@ubuntu:~$ echo ${var}
apple
wood@ubuntu:~$ read -p "Please input value of var:" var
Please input value of var:banana
wood@ubuntu:~$ echo ${var}
banana

declare,typeset

描述:

声明变量的类型

语法:

declare [-aixrp] var 

选项和参数:

-a:声明变量 var 为数组类型

-i:声明变量 var 为整数类型

-x:声明变量 var 为环境变量

-r:声明变量 var 为 readonly 类型,变量内容不可被更改,也不能 unset

-p:列出声明的变量

变量内容更改

变量内容的删除与替换

有时候利用 = 对变量内容做出修改可能比较麻烦,所以可能希望有一种方式能够直接对变量内容进行操作,直接进行更改。

修改的规则为:

变量设置方式说明

${var#keyword}

${var##keyword}

如果变量内容从头开始的数据符合 keyword,则将符合的最短数据删除

如果变量内容从头开始的数据符合 keyword,则将符合的最长数据删除

${var%keyword}

${var%%keyword}

如果变量内容从尾开始的数据符合 keyword,则将符合的最短数据删除

如果变量内容从尾开始的数据符合 keyword,则将符合的最长数据删除

${var/old_str/new_str}

${var//old_str//new_str}

如果变量内容符合 old_word,则第一个 old_str 会被 new_str 替换

如果变量内容符合 old_word,则全部 old_str 会被 new_str 替换

代码实例为:

wood@ubuntu:~$ echo ${PATH}
/opt/Anaconda3/bin:/home/wood/bin:/home/wood/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
wood@ubuntu:~$ var=${PATH}
wood@ubuntu:~$ echo ${var}
/opt/Anaconda3/bin:/home/wood/bin:/home/wood/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
wood@ubuntu:~$ echo ${var#/usr}
/opt/Anaconda3/bin:/home/wood/bin:/home/wood/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
wood@ubuntu:~$ echo ${var#*/usr}
/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
wood@ubuntu:~$ echo ${var##*/usr}
/local/games:/snap/bin
wood@ubuntu:~$ echo ${var}
/opt/Anaconda3/bin:/home/wood/bin:/home/wood/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin

以上内容只是做出了修改,但并没有进行 = 赋值保存。

wood@ubuntu:~$ echo ${var}
/opt/Anaconda3/bin:/home/wood/bin:/home/wood/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
wood@ubuntu:~$ echo ${var%/usr*}
/opt/Anaconda3/bin:/home/wood/bin:/home/wood/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:
wood@ubuntu:~$ echo ${var%%/usr*}
/opt/Anaconda3/bin:/home/wood/bin:/home/wood/.local/bin:
wood@ubuntu:~$ echo ${var}
/opt/Anaconda3/bin:/home/wood/bin:/home/wood/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin

与之前不同的是,从尾部开始匹配的情况匹配符 * 是在尾部的。但以上内容也只是做出了修改,但并没有进行 = 赋值保存。

wood@ubuntu:~$ echo ${var}
/opt/Anaconda3/bin:/home/wood/bin:/home/wood/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
wood@ubuntu:~$ echo ${var/usr/***}
/opt/Anaconda3/bin:/home/wood/bin:/home/wood/.local/bin:/***/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin
wood@ubuntu:~$ echo ${var//usr/***}
/opt/Anaconda3/bin:/home/wood/bin:/home/wood/.local/bin:/***/local/sbin:/***/local/bin:/***/sbin:/***/bin:/sbin:/bin:/***/games:/***/local/games:/snap/bin
wood@ubuntu:~$ echo ${var}
/opt/Anaconda3/bin:/home/wood/bin:/home/wood/.local/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin

变量的测试与内容替换

在 C/C++ 中,编写程序可能会使用到 define 进行预定义,其中会出现以下的语句:

#if VAR
...
#else
...
#endif

 修改的规则为:

变量设置方式str 没有设置str 为空字符串str 已设置非为空字符串
var=${str-expr}var=exprvar=var=$str
var=${str:-expr}var=exprvar=exprvar=$str
var=${str+expr}var=var=exprvar=expr
var=${str:+expr}var=var=var=expr
var=${str=expr}

str=expr

var=expr

var不变

var=

str不变

var=$str

var=${str:=expr}

str=expr

var=expr

str=expr

var=expr

str不变

var=$str

var=${str?expr}expr 输出至 stderrvar=var=$str
var=${str:?expr}expr 输出至 stderrexpr 输出至 stderrvar=$str

实例程序为:

wood@ubuntu:~$ echo ${var}

wood@ubuntu:~$ var=${var-apple}
wood@ubuntu:~$ echo ${var}
apple
wood@ubuntu:~$ unset var
wood@ubuntu:~$ echo ${var}

wood@ubuntu:~$ var=""
wood@ubuntu:~$ var=${var-apple}
wood@ubuntu:~$ echo ${var}

其余的可以对照测试。

限制关系 ulimit

这个命令可能用的不多,但是在涉及多用户共用一台主机的时候,管理员可能就要限制用户的系统资源了,此时用的就是 ulimit 命令。

描述:

限制用户的系统资源

语法:

ulimit [-SHacdfltu] [limitation]

选项与参数:

-Ssoft limit,警告的设置,可以超过这个设置值,但是如果超过这个设置值会有警告消息
-Hhard limit,严格的设置,一定不能够超过这个值
-a后面不结任何选项与参数,可以列出所有的限制额度
-c当某些程序发生错误时,系统可能会将该程序在内存中的信息写成文件,这种文件就被称为内核文件。此为限制每个内核文件的最大容量
-d程序可使用的最大段内存容量
-f此 shell 可以建立的最大文件容量,单位为 kb
-l可用于锁定的内存量
-t可使用的最大cpu时间
-u单一使用者可以使用的最大进程数量

示例为:

wood@ubuntu:~$ ulimit -a
core file size          (blocks, -c) 0
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 23512
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 1024
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 23512
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值