Shell 变量全解
变量介绍
shell变量是一种很“弱”的变量,默认情况下,一个变量保存一个串,shell不关心这个串是什么含义。所以若要进行数学运算,必须使用一些命令例如let、declare、expr、双括号等。
shell变量可分为两类:局部变量和环境变量。局部变量只在创建它们的shell中可用。而环境变量则可以在创建它们的shell及其派生出来的任意子进程中使用。有些变量是用户创建的,其他的则是专用shell变量。
变量名必须以字母或下划线字符开头。其余的字符可以是字母、数字(0~9)或下划线字符。任何其他的字符都标志着变量名的终止。名字是大小写敏感的。
给变量赋值时,等号周围不能有任何空白符。为了给变量赋空值,可以在等号后跟一个换行符。
用set命令可以查看所有的变量,unset var命令可以清除变量var,var相当于没有定义过。readonly var可以把var变为只读变量,定义之后不能对var进行任何更改。
shell变量常见引用方式如下:
引用格式 | 含义介绍 |
---|---|
${var} | 变量值。也可以写成$var,但是不推荐。 |
${#var} | 变量长度。例如var="HelloWorld",则${#var}返回值为10。 注意,引号””是界定符号,而不是变量中的字符。 |
${var:start_index} | 返回从start_index开始一直到字符串结尾。 start_index为0表示从第一个字符开始, start_index为0-x表示从倒数第x个字符开始。 例如var="0123456789"。则${var:0}返回"0123456789",${var:6}返回"6789",${var:0-3}返回”789”。 |
${var:start_index:length} | 返回从start_index开始的length个字符,length可以为负数。var="0123456789",${var:2:5}返回"23456",${var:5:-2}返回"567"(-2表示剩余2个字符不要),${var:0-3:-1}返回"78"。 |
${var#string} | 返回从左边删除string后的字符串,尽量短的去匹配。例如var="https://127.0.0.1/index.php", ${var#*/}返回"/127.0.0.1/index.php" |
${var##string} | 返回从左边删除string后的字符串,尽量长的去匹配。例如var="https://127.0.0.1/index.php",${var##*/}返回"index.php" |
${var%string} | 返回从右边删除string后的字符串,尽量短的去匹配。例如var="https://127.0.0.1/index.php",${var%/*}返回"https://127.0.0.1" |
${var%string} | 返回从右边删除string后的字符串,尽量长的去匹配。例如var="https://127.0.0.1/index.php",${var%/*}返回"https:" |
${var:-newstring} | 如果var为空,或者未定义,则返回newstring;否则返回原值。 |
${var:=newstring} | 如果var为空,或者未定义,则返回newstring,并把newstring赋值给var;否则返回原值。 |
${var:+newstring} | 如果var不为空,则返回newstring;如果var为空,则返回空值。 |
${var:?newstring} | 如果var为空或者未定义,则将newstring写入标准错误流,本语句失败;如果var不为空,则返回原值。 |
${var/substring/newstring} | 返回var中第一个substring被替换成newstring的字符串。例如var="2345432", ${var/3/Hello}返回"2Hello45432" |
${var//substring/newstring} | 返回var中所有substring被替换成newstring的字符串。例如var="2345432", ${var//3/Hello}返回"2Hello454Hello2" |
$(command) | 返回command命令执行后的所输出的结果。例如$(date),返回date命令执行后的输出,同date 命令 |
$((算数表达式)) | 返回双括号中算数运算的结果。例如$((20+5*6)),返回50 |
环境变量
环境变量的定义方法如下:
1 | export var=value |
shell在初始化的时候会在执行profile等初始化脚本,脚本中定义了一些环境变量,这些变量会在创建子进程时传递给子进程。
用env命令可以查看当前的环境变量。常用的系统环境变量如下:
环境变量 | 含义 |
---|---|
_ | 上一条命令的最后一个参数 $_ |
BASH | 展开为调用bash实例时使用的全路径名 |
CDPATH | cd命令的搜索路径。它是以冒号分隔的目录列表,shell通过它来搜索cd命令指定的目标目录。例如.:~:/usr |
EDITOR | 内置编辑器emacs、gmacs或vi的路径名 |
ENV | 每一个新的bash shell(包括脚本)启动时执行的环境文件。通常赋予这个变量的文件名是.bashrc。 |
EUID | 展开为在shell启动时被初始化的当前用户的有效ID |
GROUPS | 当前用户所属的组 |
HISTFILE | 指定保存命令行历史的文件。默认值是~/.bash_history。如果被复位,交互式shell退出时将不保存命令行历史 |
HISTSIZE | 记录在命令行历史文件中的命令数。默认是500 |
HOME | 主目录。未指定目录时,cd命令将转向该目录 |
IFS | 内部字段分隔符,一般是空格符、制表符和换行符,用于由命令替换,循环结构中的表和读取的输入产生的词的字段划分 |
LANG | 用来为没有以LC_开头的变量明确选取的种类确定locale类 |
OLDPWD | 前一个工作目录 |
PATH | 命令搜索路径。一个由冒号分隔的目录列表,shell用它来搜索命令,一个普通值为 /usr/gnu/bin:/usr/local/bin:/usr/ucb:/usr/bin |
PPID | 父进程的进程ID |
PS1 | 主提示符串,默认值是$ |
PS2 | 次提示符串,默认值是> |
PS3 | 与select命令一起使用的选择提示符串,默认值是#? |
PS4 | 当开启追踪时使用的调试提示符串,默认值是+。追踪可以用set –x开启 |
PWD | 当前工作目录。由cd设置 |
RANDOM | 每次引用该变量,就产生一个随机整数。随机数序列可以通过给RANDOM赋值来初始化。如果RANDOM被复位,即使随后再设置,它也将失去特定的属性 |
REPLY | 当没有给read提供参数时设置 |
SHELL | 当调用shell时,它扫描环境变量以寻找该名字。shell给PATH、PS1、PS2、MAILCHECK和IFS设置默认值。HOME和MAIL由login(1)设置 |
SHELLOPTS | 包含一列开启的shell选项,比如braceexpand、hashall、monitor等 |
UID | 展开为当前用户的用户ID,在shell启动时初始化 |
可以为某个命令单独设置环境变量,而不会影响后续的命令执行,比如:
1 | LD_LIBRARY_PATH=./lib:$LD_LIBRARY_PATH ./make_ext4fs |
数值变量
shell中默认把变量值当作字符串,例如:
1 | age=22 |
输出结果为22+1,而不是23,因为shell将其解释为字符串,而不是数学运算。
可以用let命令使其进行数学运算,例如:
1 | let age=${age}+1 |
也可以用typeset或者declare把变量定义为整型。例如:
1 | typeset -i age=22 |
typeset的 -i 选项把age定义为整型的了。此后每次运算,都把age的右值识别为算术表达式或数字。最终的输出结果是23
数组
在shell中可以使用数组,例如:
1 | array[0]=0 |
则array就是一个数组,也可以这样给数组初始化:
1 | array=(0 1 2) // 元素之间以空格分隔 |
数组变量操作
操作 | 介绍 |
---|---|
${array[$*]} | 访问array中某个元素 |
${#array[*]} | 返回数组元素个数 |
${array[*]} ${array[@]} |
的返回值即数组的所有元素组成的串 |
${array[*]:0:2} | 返回第一个和第二个元素组成的串。0表示开始的位置,2表示要返回的元素个数,开始位置可以为0-2(0减去2)之类的,表示从倒数第二个元素开始。 |
$array[${#array[*]}]=value | 追加数组元素 |
unset array[$i] | 删除某个数组元素 |
unset array | 删除整个数据 |
下面写个稍微复杂点的例子:
1 | for ((i=0; i<100; i++)) |
字符串转化为数组
1 | str="one two three four" |
如果字符串分隔符不是空格,则采用下面方法分割成数组:
1 |
|
OLD_IFS用于保存原分隔符,用于后续恢复。
特殊变量
变量 | 含义 |
---|---|
$0 | 当前脚本的文件名 |
$n | n是正整数。$0 当前脚本名称,$1 是第一个参数,$2 是第二个参数,等等 |
$# | 传入脚本的参数的个数 |
$* | 所有的位置参数(作为单个字符串) |
$@ | 所有的位置参数(每个都作为独立的字符串)。 |
$? | 当前shell进程中,上一个命令的返回值,如果上一个命令成功执行则$?的值为0,否则为其他非零值,常用做if语句条件 |
$$ | 当前shell进程的pid |
$! | 后台运行的最后一个进程的pid |
$- | 显示shell使用的当前选项 |
$_ | 之前命令的最后一个参数 |
$*
和$@
都表示传给脚本或者函数的参数列表,当使用双引号包裹时,"$*"
是一个字符串,而"$@"
则像一个数组:
1 | for var in "$*";do |
上述代码输入结果为:
1 | $ ./test.sh xxx yyy zzz |
指定变量类型:typeset 与 declare
declare和typeset是bash的内建命令,它们是完全相同的,可以用来限定变量的属性,如整型、大小写、宽度、左右对齐等。这是在某些编程语言中使用的定义类型不严格的方式。
当用typeset或declare改变一个变量的属性时,这种改变是永久的。
命令declare是bash版本2之后才有的,命令typeset也可以在ksh脚本中运行。
常用命令参数:
- -r 设置变量为只读
- -i 设置变量为整数
- -a 设置变量为数组array
- -f 如果后面没有参数的话会列出之前脚本定义的所有函数,如果有参数的话列出以参数命名的函数
- -x 设置变量在脚本外也可以访问到
- -u 将一个变量的字符变成大写
- -l 将一个变量的字符变成小写
变量应用举例
遍历字符串
1 | local var=$1 |