1. 变量
1.1 标量
shell变量的标量就只有字符串,数字也是当作字符串存储的。
var=hello;
echo ${#var};
可以看到hello并需要引号,所有没有$引用的都是当作字符串;不过赋值的有空格,就要用引号。
var='hello world';
var=4.13;
echo ${#var}; # 返回的是4.13的字符长度;
1.2 数组
var=(1 2 3 4); var=('hello world' 2 3 'peggy');
数组其实就是以空格隔开的标量,用var[0],var[1]等引用。
删除某个元素:unset var[2];
echo ${#var[*]}; # 返回元素个数
所以要动态向数组插入元素就用:var[${#var[*]}]='new value';
打印所有元素:echo ${var[*]};
1.3 词典(哈系表)
declare -A var;
var=(['hello world']='first' ['peggy']='second');
其实就是用字符串标量索引的数组。
删除某个元素:unset var['hello world'];
echo ${#var[*]); # 返回元素个数
动态插入更简单:var['new value']=1.23;
返回哈希的键值:${!var[*]};
1.4 与perl等脚本的不同
perl,python等脚本可以支持建立非常复杂的数据结构(如树,复杂关系的结构等等),可以说java能做的都可以做到。
但shell脚本只有上面三种数据结构,而且值都是标量;这种简单的数据支持是由于shell脚本就是为了运行shell命令行的。
2. 控制结构
2.1 循环
主要用到三种循环:次数,遍历数据,条件
for (( i = 0; i < 10; i++)) # 这个奇怪的语句仅仅为了模仿c语言。
for var in hello world peggy
do
done
这个相当与foreach语句,用来遍历数据结构。
while 或 until # 下面再说如何表达一个条件
do
done
2.2 for in的注意事项
对一个数组或哈希表循环:
var=('hello world' 'hello' 'world');
for var in ${var[*]}
do
echo $var;
done
虽然每个数组元素都是字符串,但for in只看做一个列表,一个有分隔符的列表。所以for in后面还可以直接用一个命令,通配符等等,只要返回一个列表即可。但是这个例子会循环4次,因为第一个标量有分隔符。
解决办法就是临时替换分隔符(默认是空格):
IFS.OLD=$IFS
IFS='\n'
for in
IFS=$IFS.OLD
还可以设置多个分隔符,连接即可:IFS='\n :;'
for in后面还可以直接用一个命令`command`,通配符等等,只要返回一个列表即可。
2.3 条件
if command
then
fi
表达一个条件:命令运行返回0(成功)就表示条件满足;其他测试就用test;
if test condition # 等同于 if [ condition ]
then
fi
另外有两个针对数值测试和字符串测试的符号:(( condition )) , [[ condition ]] 。
3. 运行子程序
3.1 程序组成
程序一般有几个部分:环境变量,命令行参数,输入,输出,错误输出;
环境变量可以用export导出,这样子程序就可以继承新的环境变量;
命令行参数运行程序时指定,也有的程序只接受命令行参数,不接受标准输入;
标准输入,有的子程序必须用到标准输入,命令行参数只接受配置;
3.2 输出
./ command option1 option2 arg1 arg2 > txt &>
&>相当于2>&1,即标准错误定位到标准输出;
脚本中运行子程序:var=$(command option1 arg1) # 用变量接受子程序输出,退出码在$?
也可以用``运行:var=`command option1 arg1`
3.3 输入
输入只能用管道了,输出也可以用管道。
var=echo $arg2 | command option1 arg1 # var接受最后一个程序的输出,$?是最后一个程序的退出码。
3.4 建立命令行参数
有的程序不用标准输入,把参数全用命令行参数传递;
可以用xargs这个命令转换得到命令行参数:
3.5 退出码
除了控制输入和输出外,我们经常要了解一个子程序是否执行成功。
当然可以通过查看退出码$?,但这样非常麻烦,可以用逻辑符 ||:
run command || exit 1
函数
退出码和返回值
函数被当作一个子程序执行,所以也有退出码,即函数内最后执行的一条命令的退出码。
得到子程序返回值一样:var=`function`;
参数
和普通的子shell命令一样。可以传多个参数,但是不能传递数组或哈希表。
不同
唯一特殊的就是函数可以对全局变量访问,也可以定义全局变量。但可以用local定义局部变量。