变量
变量类型
有两种类型的变量:局部变量和环境变量。局部变量仅在创建它的shell中有效,环境变量则对所有创建它的shell所派生出来的子进程都有效。某些变量由用户来创建,而另一些则是shell的特殊变量。
命名规则
变量名必须以字母或下划线开始,其余部分则可以由字符,数字(0-9)或下划线字符构成。而其他字符均可作为变量名的结束标志。名字是大写敏感的。当给一个变量赋值时,不要在等号两边留下空格。如果要将变量赋值为空,要在等号后直接跟一个换行符。创建局部变量的最简单方法时以下面的格式把值赋予变量
variable=value 例如 name=Tony
declare内置命令有两个内置命令declare和typeset可用于创建变量,通过选项还可以控制设置变量的方式。typeset命令(从Korn
shell而来)与declare命令完全一样。bash的文档中写道:typest命令完全兼容korn
shell,但是该命令并不支持内建命令声明。因此我们将使用declare内置命令。
没有参数的declare命令将列出所有设置的变量。通常只读变量时不能重新赋值或撤销的。如果有declare命令来创建只读变量,它们不能被撤销,也无法重新赋值。整型变量也能用declare来赋值。
declare variable=value declare name=Tony
declare选项
选项 | 含义 |
-r | 将变量设置为只读 |
-x | 将变量名导出到子shell中 |
-i | 将变量置为整型 |
-a | 将变量当做数组,即给元素赋值 |
-F | 只列出函数名 |
-f | 列出函数名及其定义 |
Note:-a -F 只在bash2.x版本实现 局部变量和范围
变量的范围是指变量在一个程序中的什么地方是可见的。对于shell而言,局部变量的范围限于创建变量的shell。
当给一个变量赋值时,不要在等号两个留下空格。如果要将一个变量设置空,在等号后面跟一个换行符即可。
变量前面的美元符号用于提取其存储的值。
local函数可用于创建局部变量,但这些变量只能在函数内使用。
设置局部变量。局部变量可通过将值赋予一个变量名来设置,或者使用declare来设置。
$ round=world or declare round=world
$ echo $round
# world
$ x= #赋值为空值
$ echo $x
# 空值
$ file.txt=100
# wrong, 变量名中的字符只能是字母,数字和下划线
$ name="Tony Yang"
$ echo $name
# Tony Yang
# 引号用于隐藏空格,否则shell会把字符串分割为两个单词
$ echo $$
# 父进程id
$ round=world
$ bash
# 切换到子进程
$ echo $round
# 由于是局部变量,因此子进程无法访问该变量,结果为空行
$ exit # 退出子进程
$ echo $round
# 重新可以访问变量的值
$ bash
$ round=larry
$ echo $round
# 在子进程中定义一个同名变量,然后打印它的值world
$ exit
# 退出子进程
$ echo $round
# 打印的结果为父进程的变量值world
Note:set可以查看定义的变量,unset可以清空一个变量的值。子进程定义的变量,父进程无法访问。
$ name=Tony
$ readonly name
$ echo $name
#Tony
$ unset name
# 无法清空变量,因为name是只读变量
$ name=larry
# 无法设置新值,因为name是只读变量
$ declare -r name=tony
$ unset name
$ name=larry
# 结果同上面一样
环境变量
环境变量是能为创建它的shell及其派生子进程所用的变量,它们也经常被称为全局变量以区分与局部变量。一般约定环境变量为大写,它们是那些可以通过内置命令export导出的变量。
创建环境变量的shell称为父shell,从shell中启动的新shell称为子shell。环境变量被传送给任何从创建该变量的shell中派生的shell。这些变量可以从父shell传给子shell,再传给孙shell,以此类推,但反方向不行。即,shell能创建变量,但是它无法将变量传给其父shell,而只能传给它的子shell。某些环境变量,如HOME,LOGNAME,PATH已经SHELL,是在登录前由/bin/login程序来设置的。通常环境变量在用户主目录下的.bash_profile文件中定义。
设置环境变量
要设置环境变量,必须在给变量赋值或设置了变量后使用export命令,内置命令built-in加上-x选项也可以完成同样的事情(在导出一个变量时,不需要用美元符号)。
export variable=value
variable=value;export variable
declare -x variable=value
实例
$ export NAME=tony
$ PS1='\d:\W:$USER>';export PS1
$ declare -x TERM=linux
export命令选项
选项 | 值 |
– | 选项段的结束标志,余下的都是参数 |
-f | name-value 形式被视为函数而不是变量 |
-n | 将全局变量(已导出的)转换为局部变量,该变量将不会导出到子进程中 |
-p | 显示所有的全局变量 |
Note:变量的继承(派生)是单向的,只能由父传子)
$ export TERM=linux or declare -x TERM=linux
$ NAME="tony yang"
$ export NAME
$ echo $NAME
$ echo $$
$ bash
$ echo $$ # 子shell
$ echo $NAME # 依然可以访问从父shell继承的变量NAME
$ declare -x NAME="larry wall" # 在子shell中声明一个环境变量
$ echo $NAME
$ exit
$ echo $NAME #此时回到父shell,NAME的值依然为tony yang,因为环境变量是无法子传父的。
# tony yang
清空变量
如果未被设置为只读属性的话,本地变量和环境变量都可以通过使用unset命令清空
unset name; unset TERM
# unset把变量从shell内存中删除
$ declare num=100
$ set | grep num #可以查看到该变量
$ unset num; set | grep num # num变量被删除
打印变量的值:echo命令内建命令echo的作用是将其参数打印到标准输出。-e选项使得echo命令可以无限制地使用转义序列控制输出的效果。
echo选项含义
选项 | 解释 |
-e | 允许翻译如下所有的转义序列 |
-n | 把换行符压缩到输出行的末尾 |
-E | 关闭对转义符号的翻译,包括关闭对那些默认情况下翻译的转义符号的翻译 |
转义序列
转义符 | 解释 |
\a | 警告(铃声) |
\b | 退格 |
\c | 不换行打印 |
\f | 填表 |
\n | 换行 |
\r | 返回 |
\t | 制表符 |
\v | 垂直制表符 |
\ | 反斜杠 |
\nnm | ASCII代码为nmm的符号 |
$ echo The username is $LOGNAME
$ echo -e "\t\thello there\c"
# 打印转义序列已经字符串内容
$ echo -n "hello there"
# 打印行,不换行
$ echo -E "\t\thello world"
# 打印行,关闭转义字符的解释,安装字面内容打印
# \t\thello world
printf命令.用来格式化输出,作用是用来打印格式化字符串,效果类似c语言的printf函数。格式包括字符串本身和描述打印效果的字符。定义格式的方法是在%后面跟一个说明符,例如%f表示后面是一个浮点数,%d表示一个整数。
格式 printf format [arguments...]
$ printf '%10.2f%5d\n' 10.5 25
# 10.50 25
$ type printf
# printf is a built-in
$ printf "The number is %.2f\n" 100
# The number is 100.00
$ printf "%-20s%-15s%10.2f\n" "jody" "savage" 28
# jody savage 28.00
$ printf "%s's average was %.1f%%.\n" "jody" $(( (80 + 70 + 90)/3 ))
# jody's average was 80.0%.
变量扩展修改符(参量扩展)。通过特定的修改符,可以检验和修改变量。这些修改符提供了一个快捷的方法来检验变量是不是被设置过,并把输出结果输出到一个变量中。见下表
变量修改符
修改符 | 解释 |
${variable:-word} | 如果变量被设置了而且非空(null)就保持原来的值,否则设置为word |
${variable:=world} | 如果变量被设置了而且非空就保持原来的值,否则就把变量永久设置为word |
${variable:+world} | 如果变量被设置了而且非空就替代word,否则什么也不做 |
${variable:?word} | 如果变量被设置了而且非空就保持原来的值,否则就打印word,然后退出shell。如果word为空就打印parameter null or not set |
${variable:offset | 从offset位置开始提取变量的值得子字符串,如果offset为0就取整个字符串 |
${variable:offset:length | 从变量值的offset位置开始提取长度为length的子字符串 |
使用冒号和修改符来检验变量是否被设置,是否为空。若没有冒号,即使设置为null的变量也被认为是已被设置过值。
$ fruit=peach
$ echo ${fruit:-world}
# peach
$ echo ${newfruit:-apple}
# apple
$ name=
$ echo ${name:-joe}
# joe #=> 这两种方法相同,结果一样
$ echo ${name:-joe}
# joe
$ echo $name
# 空值
Note: 以上这种方法只是临时赋值,并不会永久保存在name变量里面
$ name=
$ echo ${name:=peter}
# peter
$ echo $name
# peter
Note:
以上这种方法会永久赋值,会将值暂时的永久保留在变量里,除非手动清除或者赋新值
$ foo=grapes
$ echo ${foo:+apple}
# apple
$ echo $foo
# grapes
Note:以上这种方法与:-方法正好相反,当foo值不为null时,会临时改变它的值,但是不是永久改变,因此再次打印foo的时候,值依然是原来的grapes
$ echo ${namex:?"namex is undefined"}
# 因为namex为null,因此会打印后面的字符串内容即namex is undefined
$ echo ${y:?} or echo ${y?}
# parameter null or not set
$ var=notebook
$ echo ${var:0:4}
# note
$ echo ${var:4:4}
# book
$ echo ${var:0:2}
# no
子字符串的变量扩展。模式匹配参数用来从字符串的前面或者后面,去掉特定的部分字符串。最常用的方法就是从路径中去点路径。
表达式 | 功能 |
${variable%pattern} | 变量的值与模式符合smallest trailing portion就删除它 |
${variable%%pattern} | 变量的值与模式符合largest trailing portion就删除它 |
${variable#pattern} | 变量的值与模式符合smallest leading portion就删除它 |
${variable##pattern} | 变量的值与模式符合largest leading portion 就删除它 |
${#variable} | 替换变量中字母的个数,如果*或者@,长度就是位置参量的个数 |
$ pathname="/usr/bin/local/bin"
$ echo ${pathname%/bin*}
# 从尾部开始删除最小匹配的内容即/bin/
$ pathname = "/usr/bin/local/bin"
$ echo ${pathname%%/bin*}
# 从尾部开始删除最大匹配的内容即/bin/local/bin/
$ pathname="/home/tony/.bashrc"
$ echo ${pathname#/home}
# 从头开始,删除最小匹配的内容即/home
$ pathname="/home/tony/.bashrc"
$ echo ${pathname##*/}
# 从头开始,删除最大匹配的内容即/home/tony/
$ name="Ebenezer Scrooge"
$ echo ${#name}
# 打印赋值给变量name的字符串的字母个数,这里共有16个字母
位置参量。通常情况下,特定的内建变量,被称为位置参量,它们被用于从命令行向脚本传递参数,或者在函数中用于保存传递给函数的参数。这些变量称为位置参量是因为它们以数字1,2,3…区分,这些数字与它们在参量清单中的位置有对应关系。
shell脚本的名字保存在变量$0中,位置参量可以被set命令设置,重置和清空。
表达式 | 功能 |
$0 | 当前脚本的名字 |
$1-9 | 位置参数1-9 |
${10} | 位置参量10 |
$# | 位置参量的个数 |
$* | 向所有的位置参量赋值 |
$@ | 同$*, 有双引号时除外 |
“$*” | 赋值到"$1$2$3"等等 |
“$@” | 赋值到"$1" “$2” "$3"等等 |
$ set punky tommy bert jody
$ echo $*
# punky tommy bert jody
$ echo $@
# punky tommy bert jody
$ echo $#
# 4
$ set a b c d e f g h i j
$ print $10
# a0 不会解释为$10,而是解释为$1 + 0,因此需要加上一个花括号来避免这种情况
$ set file1 file2 file3
$ eval echo \$$#
# file3 首先$#会被替换为3,然后eval会将字符串$3解释为位置参数$3,此时该变量的值为file3,因此结果为file3
$ set --
# 清空所有位置参量
其他特殊变量
shell有一些由单个字符组成的变量,在这些变量前加上$后就能访问这些变量,见表
变量 | 含义 |
$ | shell的PID |
- | 当前sh的选项 |
? | 最后一个命令的退出状态值 |
! | 最后一个放入后台作业的PID值 |
$ echo The pid of this shell is $$
$ echo "The options for this shell are $-"
# 打印当前交互式bash的选项
$ grep root /etc/passwd
$ echo $?
# 打印最后一个命令执行的退出状态值,成功返回0,失败返回1
$ sleep 10 &
$ echo $!
# 打印最后一个被放入后台的作业PID号