变量的取用
变量在取用时,前面需要加上钱字号 “$”。
echo $variable
echo ${variable}
echo $PATH
echo ${PATH}
变量的设置与修改
myname=Dawn # 设置变量 myname 的内容为 Dawn
echo ${myname}
unset myname # 取消 myname 的设置
bash 中假如 echo 一个没有设置内容的变量时,它会显示空的值。但是在某些 shell 中,去 echo 这种变量可能会出现错误。
变量的设置与修改需要注意以下几点:
-
变量名称只能是英文、字母、数字,开头不能是数字。
-
等号两边不能直接接空白字符,如
myname = VBird
。 -
变量内容若有空白字符可使用双引号
""
,或单引号''
将变量内容结合起来。- 双引号内的特殊字符如 $ 等将会保有原本的特性,如
var="lang is $LANG"
,echo 则会得到 lang is en_US.UTF-8。 - 单引号的特殊字符就会被当成一般字符。
- 双引号内的特殊字符如 $ 等将会保有原本的特性,如
-
可使用
\
将特殊符号([Enter]、$、\
、单引号、双引号、反单引号)转换为一般字符。 -
在一串指令中,还需要借由其他额外的指令所提供的的信息时,可以使用反单引号或者 $。比如
version=$(uname -r)
,那么echo $version
的时候就会得到 20.1.0。# 进入当前 kernel 的模块目录 cd /lib/modules/`uname -r`/kenrel cd /lib/modules/$(uname -r)/kernel # 这种方式更好 # 上述这种方式其实作了两次动作 # - 先进行反单引号内的动作,得到结果 # - 再将结果带入原指令
-
若要为变量扩展内容时,则可用
$变量名称
或${变量}
累加内容,如PATH=${PATH}:/home/bin
。 -
通常大写字符为系统默认变量或者环境变量,自行设置变量可以使用小写字符,方便判断。一般来说,不论是否是环境变量,只要跟正在使用的 shell 的操作接口有关的变量都会被设置为大写字符。
当你有一个常去的工作目录,比如 /home/dawnguo/workspace,怎么使得 cd 到这个目录的动作简化呢?我们可以设置一个变量
work=/home/dawnguo/workspace
(这个变量可以在 bash 的配置文件 .bashrc 中直接指定),接下去使用cd $work
就好了。
变量的有效范围
Bash 中的变量也有范围,默认情况下用户在一个 shell 中定义的变量是不会传到子进程中去的。若希望该变量在其他子进程也可以执行,那么则需要 export 来使变量变成环境变量,如 export PATH
。目前这个 shell 的情况下,去启用一个新的 shell 时,新的 shell 就是子进程。假如没有使用 export,那么父进程的自定义变量是无法在子进程中使用的。但是使用 export 将其变为环境变量之后就可以在子进程中使用了。
变量从键盘读取
要想读取来自键盘输入的变量,就需要 read 这个指令。
read: 读取来自键盘输入的变量内容
-p:后面可以接提示字符!
-t:后面可以接等待的“秒数!”这个比较有趣~不会一直等待使用者啦!
# 将键盘输入的内容作为 demo 这个变量的内容
$ read demo
# 30s 之内输入,如果 30s 之内没有任何输入,那么会自动略过。假如 30s 之内有输入,那么输入的内容将会作为变量 named 的内容。
$ read -p "Please enter your name: " -t 30 named
声明变量
变量类型默认为“字符串”,假如想要声明变量为其他类型,需要使用 declare 或者 typeset(两个是一样的功能)。如果 declare 后面没有接任何参数,那么 bash 就会将所有的变量名称和内容通通列出来,就好像 set 一样。
declare [-aixr] variable
-a :将后面名为 variable 的变量定义成为阵列 (array) 类型
-i :将后面名为 variable 的变量定义成为整数数字 (integer) 类型
-x :用法与 export 一样,就是将后面的 variable 变成环境变量;
-r :将变量设置成为 readonly 类型,该变量不可被更改内容,也不能 unset,只能退出登陆才能恢复哦
-p :可以单独列出变量的类型
+x :将 - 变成 + 可以取消 x 动作
# echo 的话会显示设置的内容,而不会进行相加
$ sum=100+30+50
# 这种情况下会进行相加
$ declare -i sum=100+30+50
需要注意的是 bash 中的数值运算,默认最多仅能到达整数形态,所以 1/3 结果为 0。
array 变量类型
在 bash 里面设置 array 类型的变量(目前 bash 提供的只有一维阵列),如下所示。
$ declare -a var[index]=content
$ var[1]="small min"
$ var[2]="big min"
$ var[3]="nice min"
$ echo ${var[1]}
变量内容的删除、取代与替换
变量除了可以直接设置来修改原来的内容之外,还可以对变量的内容进行删除、取代与替换。
变量内容的删除与取代
# 格式是:{variable#/*local/bin:}
# - variable 就是变量的名称,比如上面的 path
# - # 表示从变量内容的最前面开始往右删除,但是仅删除最短匹配的那个
# - ## 表示从变量内容的最前面开始往右删除,但是删除的是最长匹配的那个
# - /*local/bin: 相当于匹配模式,用于匹配符合模式的字符串
$ path=${PATH}
$ echo $path
/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
# 删除从左到第一个 local/bin 的路径
$ echo ${path#/*local/bin:}
/usr/bin:/bin:/usr/sbin:/sbin
# 删除第一个匹配 /*: 的内容,即删除第一个路径
$ echo ${path#/*:}
/usr/bin:/bin:/usr/sbin:/sbin
# 删除前面所有的路径,仅保留最后一个目录
$ echo ${path##/*:}
/sbin
# % 从右往左开始删除内容,最后一个假如含 bin 的话,则删除最后一个目录
$ echo ${path%:*bin}
/usr/local/bin:/usr/bin:/bin:/usr/sbin
# %% 则是最长匹配,删除只剩一个目录了
$ echo ${path%%:*bin}
/usr/local/bin
# 将 path 变量内容内的 sbin 替换为 SBIN
$ echo ${path/sbin/SBIN}
/usr/local/bin:/usr/bin:/bin:/usr/SBIN:/sbin
# 如果是两条斜线,那么所有符合的内容都会被替换
$ echo ${path//sbin/SBIN}
/usr/local/bin:/usr/bin:/bin:/usr/SBIN:/SBIN
更加完整的设置方式如下所示:
变量设置方式 | 说明 |
---|---|
${变量#关键字} ${变量##关键字} | 若变量内容从头开始的数据符合“关键字”,则将符合的最短数据删除;若变量内容从头开始的数据符合“关键字”,则将符合的最长数据删除 |
${变量%关键字} ${变量%%关键字} | 若变量内容从尾向前的数据符合“关键字”,则将符合的最短数据删除;若变量内容从尾向前的数据符合“关键字”,则将符合的最长数据删除 |
${变量/旧字串/新字串} ${变量//旧字串/新字串} | 若变量内容符合“旧字串”则“第一个旧字串会被新字串取代”;若变量内容符合“旧字串”则“全部的旧字串会被新字串取代” |
变量的测试与内容替换
在某些时刻我们需要判断某个变量是否存在,若变量存在则使用既有的设置,若变量不存在则给予一个常用的设置。
# username 假如没有设置的话,那么 username 被设置为 root
$ username=${username-root}
$ echo ${username}
root
$ username=dawn
$ username=${username-root}
$ echo ${username}
dawn
# 格式如下:new_var=${old_var-content}
# - new_var 是新的变量用来替换 old_var。new_var 和 old_var 常常是一样的
# - content 假如 old_var 没有被设置的话,那么则设置为 content 的内容
# 假如 username 没有被设置或者设置为空串,那么 username 则被设置为 root
$ username=${username:-root}
$ echo ${username}
root
# 假如 str 不存在,那么 str 和 var 的内容都将被设置为 newvar
$ unset str; var=${str=newvar}
$ echo "var=${var} str=${str}"
var=newvar str=newvar
# 假如 str 存在,那么 str 和 var 的内容都将被设置为 oldvar
$ str="oldvar"; var=${str=newvar}
bash-3.2$ echo "var=${var} str=${str}"
var=oldvar str=oldvar
# 假如 str 不存在,那么 var 的测试结果直接显示 “novar”
$ unset str; var=${str?novar}
bash: str: novar
# 假如 str 存在,那么 var 的内容与 str 的内容一样
$ str="oldvar"; var=${str?novar}
$ echo "var=${var} str=${str}"
var=oldvar str=oldvar
更加完整的替换表格如下,一般来说,str
表示仅为“没有该变量”,str:
表示 str 没有设置或者设置成了空串。
变量设置方式 | str 没有设置 | str 为空字串 | str 已设置非为空字串 |
---|---|---|---|
var=$ | var=expr | var= | var=$str |
var=$ | var=expr | var=expr | var=$str |
var=${str+expr} | var= | var=expr | var=expr |
var=${str:+expr} | var= | var= | var=expr |
var=$ | str=expr var=expr | str 不变 var= | str 不变 var=$str |
var=$ | str=expr var=expr | str=expr var=expr | str 不变 var=$str |
var=${str?expr} | expr 输出至 stderr | var= | var=$str |
var=${str:?expr} | expr 输出至 stderr | expr 输出至 stderr | var=$str |
环境变量
常用命令
-
env 查看环境变量与常见环境变量说明。env 是 environment 的简写,会列出来所有的环境变量。
-
set 查看所有变量(含环境变量与自定义变量)。set 除了将环境变量显示出来之外,还会将 bash 中的其他变量都显示出来。
-
export 将自定义变量(局部变量)转成环境变量(全局变量)。自定义变量和环境变量的区别在于该变量能否被子进程所继续使用,子进程仅会继续父进程的环境变量,不会进程父进程的自定义变量。export 后面没有接要导出的变量时,那么会把所有的环境变量显示出来。
在理论上为什么环境变量的数据可以被子进程所引用呢?这是因为内存配置的关系:
- 当启动一个 shell 之后,操作系统会分配一内存区域给 shell 使用,此内存中的变量可以给子进程使用;
- 若在父进程中使用 export ,那么可以让自定义变量的内容写到上述的内存区域中(环境变量);
- 当启动一个新的 shell 时,子 shell 可以将父 shell 环境变量所在的内存区域导入自己的环境变量区域中。
这个环境变量跟 bash 的操作环境有点不大一样,PS1 并不是环境变量,但是会影响到 bash 的提示字符。
常见系统变量
-
HOME 代表使用者的主目录。
-
SHELL 表示目前这个环境使用的是哪个 SHELL。
-
HISTSIZE 表示历史命令的数量。
-
PATH 就是可执行文件搜索的路径啦,目录和目录中间以冒号(:)分隔,由于文件的搜索依序由 PATH 的变量内的目录来查询,所以目录的顺序也是很重要的。
当下达 ls 这个指令时,系统就是通过 PATH 这个变量里面的内容所记录的路径顺序来寻找指令的呢!如果在搜索完 PATH 变量内的路径还找不到 ls 这个指令时,就会在屏幕上显示 “command not found” 的错误讯息。
-
LANG 是语系数据的变量,也就是编码相关的变量。Linux 到底支持多少语系,我们可以使用
locale -a
这个指令来进行查询。而查看当前除 LANG 这个变量之外,其他跟语系相关的变量可以使用locale
这个指令(不加任何参数)查询得到。$ locale LANG="zh_CN.UTF-8" LC_COLLATE="zh_CN.UTF-8" LC_CTYPE="zh_CN.UTF-8" LC_MESSAGES="zh_CN.UTF-8" LC_MONETARY="zh_CN.UTF-8" LC_NUMERIC="zh_CN.UTF-8" LC_TIME="zh_CN.UTF-8" LC_ALL=
上面这些变量都是跟语系相关的,假如其他变量你都未设置,仅仅设置了 LANG 或者 LC_ALL 这两个变量,那么其他的变量都会被这两个变量所取代。这也是为啥在 Linux 中仅设置 LANG 和 LC_ALL 这两个变量就可以了。
有时候 Linux 主机的终端机接口(tty1 ~tty6)的环境下,虽然设置了中文的语系,但是还是会有一堆乱码。这是因为终端机接口环境下无法显示像中文这么复杂的编码文字,所以会产生乱码。这个时候就需要在 tty1~tty6 的环境下加装一些中文化接口的软件,才能看到中文。此时,通过 ssh 的方式可能会看到中文,因为 ssh 的终端软件支持中文。
-
RANDOM 是随机数的变量了,目前大多数的 distributions 都会有乱数产生器,就是 /dev/random 这个文件。可以通过这个乱数文件相关的变量 $RANDOM 来随机取得数据,这个值介于 0~32767。
假如想要取得 0~9 之间的数值的话,那么可以如下所示:
declare -i number=$RANDOM*10/32768; echo $number
-
MAIL 当使用 mail 这个指令收信时,系统会读取的邮件信箱文件。
其他常用变量
-
PS1 提示字符的设置,也就是输入命令前面的提示内容,比如 root@pc~。每次按下 [Enter] 按键去执行某条指令后,最后需要再出现提示字符的时候就会主动读取这个变量值了。PS1 中设置的内容是一些特殊符号,这些符号会显示不同信息,如下所示,更详细的可以使用
man bash
。- \d :可显示出“星期 月 日”的日期格式,如:"Mon Feb 2"
- \H :完整的主机名称。举例来说,鸟哥的练习机为“study.centos.vbird”
- \h :仅取主机名称在第一个小数点之前的名字,如鸟哥主机则为“study”后面省略
- \t :显示时间,为 24 小时格式的“HH:MM:SS”
- \T :显示时间,为 12 小时格式的“HH:MM:SS”
- \A :显示时间,为 24 小时格式的“HH:MM”
- @ :显示时间,为 12 小时格式的“am/pm”样式
- \u :目前使用者的帐号名称,如“dmtsai”;
- \v :BASH 的版本信息,如鸟哥的测试主机版本为 4.2.46(1)-release,仅取“4.2”显示
- \w :完整的工作目录名称,由根目录写起的目录名称。但主文件夹会以 ~ 取代;
- \W :利用 basename 函数取得工作目录名称,所以仅会列出最后一个目录名。
- \#:下达的第几个指令。
- $ :提示字符,如果是 root 时,提示字符为 # ,否则就是 $ 啰~
假如要设置成下面这样的效果,其中 12 表示第 12 条指令,那么 PS1 可以如下这样设置
PS1='[\u@\h \w \A #\#]\$ '
-
$,当前 shell 的 PID。
echo $$
-
? 上一条执行的指令的回传值。当我们执行某些指令时,这些指令都会回传一个执行后的代码,一般来说,如果成功地执行了指令,则会回传一个 0 值;执行过程发生了错误,那么会回传“错误代码”。
-
OSTYPE, HOSTTYPE, MACHTYPE,主机硬件与 kernel 的等级。比如 linux-gnu、x86-64。