1.shell脚本和函数
1.1.函数
2.shell变量
2.1.位置参数
可以使用varname=value的语句定义变量值,例如:
hatter=mad
echo "$hatter"
mad
最重要的特定内置变量称为位置参数,当脚本被调用时,它们保存脚本的命令参数。位置参数名为1,2,3等,其值由$1,$2,$3表示。
还有一个位置参数0,其值为脚本名。
还有两个特殊变量包含了所有的位置参数(出了位置参数0):*和@。它们的差别不明显但很重要,并且只有在双引号内才体现出来。
“$*”是包含所有参数位置的单一字符串,由环境变量IFS(内部域分隔符,internal field seperator)中第一个字符分隔。IFS默认为
空格、TAB和NEWLINE。另一方面,“$@”等价于“$1”"$2"...."$N",这里N为位置参数数目,等价于N个单独的由空格分隔的双引号
字符串。如果没有位置参数,“$@”为空。
最后“$#”是参数的数量。
使用如下脚本params进行测试:
echo "$@"
echo "$*"
echo "$0 $1 $2 $3"
echo "$#"
执行的结果是:
./params 1 2 3
1 2 3
1 2 3
./params 1 2 3
3
2.2.函数内位置参数
shell函数使用位置参数和特殊变量,如*和#,其方式与shell脚本一样,典型情况下,在一个shell脚本里都要定义几个shell函数,
因此每个函数都要处理自己的参数,这表明每个函数都要分别跟踪位置参数,每个函数都有这些变量的副本,我们称这些变量
对函数是局部的。
然而,在函数内定义的其他变量则不是局部的,其取值在整个shell脚本中均为已知。
使用如下脚本进行测试:
func_a()
{
echo "$0,$1,$2"
var1="var1 in func_a"
echo "var1:$var1"
}
var1="var1 out func_a"
echo "var1:$var1"
func_a arg1 arg2
echo "var1:$var1"
echo "$0,$1,$2"
执行脚本:
$./var.sh 1 2
var1:var1 out func_a
./var.sh,arg1,arg2
var1:var1 in func_a
var1:var1 in func_a
./var.sh,1,2
在函数外定义的var1被函数内的赋值给覆盖了。
2.3.函数内局部变量
函数定义中的local定义使所涉及的变量均为函数的局部变量。将上面的脚本修改如下:
func_a()
{
echo "$0,$1,$2"
local var1="var1 in func_a"
echo "var1:$var1"
}
var1="var1 out func_a"
echo "var1:$var1"
func_a arg1 arg2
echo "var1:$var1"
echo "$0,$1,$2"
执行结果:
$./var.sh 1 2
var1:var1 out func_a
./var.sh,arg1,arg2
var1:var1 in func_a
var1:var1 out func_a
./var.sh,1,2
此时在函数内的var1变成了局部变量。
2.4.对$@和$*进行引用
为什么“$*”用IFS的第一个字符而不是用空格分隔呢,这时为了输出的灵活性。下面是一个简单的例子,打印逗号分隔的位置参数
列表,脚本为:
IFS=,
echo "$*"
运行结果为:
$./a.sh 1 2 3
1,2,3
为什么“$@”用作N个独立的双引号引用字符串呢?目的是允许你再次分别使用它们。
2.5.变量语法详解
取一个变量值的$varname的语法实际上是常用语法${varname}的简化形式。
为什么要有两种语法呢,一个原因是,如果代码中引用了多余9个位置参数,则必须使用${10}而不是$10.
使用如下脚本进行测试:
echo "$0 $1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $20"
运行结果:
$./params 1 2 3 4 5 6 7 8 9 0
./params 1 2 3 4 5 6 7 8 9 10
$10被解释为$1后面跟一个字符0,所以$10为10.
还要考虑下面情况,如果要在用户ID后面放一个下划线。
echo $UID_
shell会试图使用UID_作为变量名。必须使用${UID}_
3.字符串操作
替换操作符:
${varname:-word}
如果varname存在并且非null,返回其值,否则返回word。
${varname:=word}
如果varname存在并且非null,返回其值,否则将其设置为word,然后返回其值。位置参数和特殊餐宿不能这样设置。
${varname:=?message}
如果varname存在并且非null,返回其值,否则打印varname:message,并推出当前命令或脚本。省略message则产生默认
信息:parameter null or not set。
${varname:+word}
如果varname存在并且非null,返回word,否则返回null。
${varname:offset}
${varname:offset:length}
执行字符串扩展。返回$varname从offset开始,长度为length的子字符串。如果长度省略,字符串从offset开始,一直到$varname
结束。如果varname为@,length则为从参数offset开始的位置参数的数目。
模式匹配操作符:(模式可能包含任意字符的字符串,用于字符设置和范围的*,?和[])
${variable#pattern}
如果模式匹配变量取值的开头,删除最短的匹配部分,返回剩余部分。
${variable##pattern}
如果模式匹配变量取值的开头,删除最长的匹配部分,返回剩余部分。
${variable%pattern}
如果模式匹配变量取值的结尾,删除最短的匹配部分,返回剩余部分。
${variable%%pattern}
如果模式匹配变量取值的结尾,删除最长的匹配部分,返回剩余部分。
${variable/pattern/string}
${variable//pattern/string}
将variable中匹配模式的最长部分替换成string。第一种格式中,只有第一个匹配部分被替换,第二种格式中,所有匹配部分均被
替换。如果模式以#开头,必须匹配variable的开头。如果以%开头,则必须匹配variable的结尾。如果string为null,匹配部分被删除。
如果variable为@或*,操作为依次应用于每个位置参数并且扩展为结果列表。
长度操作符:
${#varname}返回变量字符串的长度。
4.命令替换
命令替换允许你使用命令的标准输出,就好像它是一个变量值一样。命令替换的语法是:
$(command)
运行圆括号内的命令,该命令写到标准输出的内容返回作为表达式值。