基本格式
#!/bin/bash
echo 'Hello World'
#!/bin/bash
:脚本的第一行声明了脚本的解释器,对于 shell 脚本解释器通常为 /bin/bash
,当然如果是 python 脚本也可以写成 #!/bin/python
。
第一行之后的所有内容就是具体的命令,变量以及函数了。
运行方式
# 使用脚本中声明的解释器解释执行,如果未声明则使用当前 shell 解释执行。
./script.sh
# 使用指定的解释器执行
# 使用 /bin/sh 解释执行
sh script.sh
# 使用 /bin/bash 解释执行
bash script.sh
变量
永久环境变量
本质属于文件,对于所有 shell 均可访问。
临时环境变量
只允许当前 shell 以及其子 shell 访问。一般通过 export
来设置。
export VAR_NAME=alice
临时变量
仅仅允许当前 shell 访问。直接在声明即可。shell 脚本中不存在高级语言中局部变量这个概念,也就是 shell 脚本中任何位置声明的变量均为全局变量。
var1=1
特殊变量
变量 | 含义 |
$0 | 当前脚本的文件名 |
$n | 传递给脚本或函数的参数。n 是一个数字,表示第几个参数。例如,第一个参数是$1,第二个参数是$2。 |
$# | 传递给脚本或函数的参数个数。 |
$* | 传递给脚本或函数的所有参数。 |
$@ | 传递给脚本或函数的所有参数。被双引号(” “)包含时,与 $* 稍有不同,下面将会讲到。 |
$? | 上个命令的退出状态,或函数的返回值。 |
$$ | 当前Shell进程ID。对于 Shell 脚本,就是这些脚本所在的进程ID。 |
\$* 和 \$@
这两个变量在不使用双引号包裹的时候完全一样
#!/bin/bash
function foo()
{
for var in $*
do
# -e 表示启用转义字符
echo -e "$var\n"
done
}
foo 1 2 3 4 5
#!/bin/bash
function foo()
{
for var in $@
do
# -e 表示启用转义字符
echo -e "$var\n"
done
}
foo 1 2 3 4 5
上面两个脚本的执行结果一样:
1 2 3 4 5
但是一旦被双引号包裹就不一样了
#!/bin/bash
function foo()
{
for var in "$*"
do
# -e 表示启用转义字符
echo -e "$var\n"
done
}
foo 1 2 3 4 5
输出为 1 2 3 4 5
[换行]
#!/bin/bash
function foo()
{
for var in $@
do
# -e 表示启用转义字符
echo -e "$var\n"
done
}
foo 1 2 3 4 5
输出结果依旧为
1 2 3 4 5
基础算数运算
可以进行简单的四则运算。但是 bash 不支持浮点运算,所以除法会直接截断小鼠部分。同时由于 *
在 shell 中有特殊的含义,所以必须使用 \
进行转义才能使用乘法。
# 结果为 3
expr 1 + 2
# 结果为 -1
expr 1 - 2
# 结果为 6
expr 2 \* 3
# 结果为 2
expr 5 / 2
条件判断
Shell中的 test
命令用于检查某个条件是否成立,它可以进行数值、字符和文件三个方面的测试。 test
可以用 []
代替,如 test $var1 -eq $var2
与 [ $var1 -eq $var2 ]
等价。但是不允许省略空格,也就是说 [$var1 -eq $var2]
是错的。
数字比较
参数 | 作用 | 举例 |
-eq | 相等则为真 | test $var1 -eq $var2 |
-ne | 不等则为假 | test $var1 -ne $var2 |
-gt | 大于则为真 | test $var1 -gt $var2 |
-ge | 大于等于则为真 | test $var1 -ge $var2 |
-lt | 小于则为真 | test $var1 -lt $var2 |
-le | 小于等于则为真 | test $var1 -le $var2 |
字符串比较
参数 | 作用 | 举例 |
= | 等于则为真 | test $str1 = $str2 |
!= | 不等则为真 | test $str1 != $str2 |
-z | 字符串长度为零则为真 | test -z $str1 |
-n | 字符串长度不为零则为真 | test -n $str1 |
文件判断
参数 | 作用 | 举例 |
-e | 如果文件存在则为真 | test -e $filename |
-r | 如果文件存在且可读则为真 | test -r $filename |
-w | 如果文件存在且可写则为真 | test -w $filename |
-x | 如果文件存在且可执行则为真 | test -x $filename |
-s | 如果文件存在且至少有一个字符则为真 | test -s $filename |
-d | 如果文件存在且为目录则为真 | test -d $filename |
-f | 如果文件存在且为普通文件则为真 | test -f $filename |
-c | 如果文件存在且为字符型特殊文件则为真 | test -c $filename |
-b | 如果文件存在且为块特殊文件则为真 | test -b $filename |
流程控制
if
语法
if boolean ; then
# TODO
fi
if boolean
then
# TODO
fi
举例
shell 代码
#!/bin/bash
if [ 1 -eq 2 ] ; then
echo '1 == 2'
等价 C 代码
if (1 == 2) {
printf("1 == 2");
}
if···else
语法
if boolean ; then
# TODO
else
# TODO
fi
if boolean
then
# TODO
else
# TODO
fi
举例
shell 代码
#!/bin/bash
if [ 1 -eq 2 ] ; then
echo '1 == 2'
else
echo '1 != 2'
fi
等价 C 代码
if (1 == 2) {
printf("1 == 2");
} else {
printf("1 != 2");
}
if···elif
if boolean ; then
# TODO
elif boolean ; then
# TODO
fi
if boolean
then
# TODO
elif boolean
then
# TODO
fi
for
语法
for var in item0 item1 item2 ....
do
# TODO
done
举例
#!/bin/bash
for num in 1 2 3 4 5
do
# -e 代表开启字符转义
echo -e "${num}\n"
done
结果
1 2 3 4 5
while
语法
while boolean
do
# TODO
done
举例
shell 代码
#!/bin/bash
max=6
num=0
while [ $num -lt $max ]
do
echo -e "${num}\n"
num=`expr $num + 1`
done
等价 C 代码
int max = 6, num = 0;
while (num < max) {
printf("%d\n", num);
num += 1;
}
函数
语法
# 声明函数(无论有无参数括号内均为空)
function name()
{
# TODO
return value
}
# 调用参数,后面跟上若干的参数
name 1 2 3 ...
其中 function 可以省略,return 也可以省略,返回值默认为最后一条指令的执行结果,return 只允许接数字,且范围为$[0,255]$。
举例
#!/bin/bash
function sum()
{
ret=0
for num in $@
do
ret=`expr $ret + $num`
done
return $ret
}
# 计算 1 + 2 + 3
sum 1 2 3
echo $?
双引号、单引号和反引号
双引号
双引号中允许使用变量。
#!/bin/bash
str=World
echo "Hello $str"
结果为 Hello World。
单引号
单引号中的内容将原文输出,但是不对转义符生效。
#!/bin/bash
str=World
echo 'Hello $str'
结果为 Hello $str。
反引号
会将反引号中的命令作为返回值
#!/bin/bash
list=`ls`
echo $list
结果是当前目录中的文件。
$()
$()
类似函数一样让我们将某个命令赋值给某个变量,当使用该变量时才会执行对应的命令并将返回值作为变量的值。
(())
扩展运算,支持了 C 语言大部分的写法。
- 在双括号结构中,所有表达式可以像c语言一样,如:
a++
,b--
等。 - 在双括号结构中,所有变量可以不加入:
$
符号前缀。 - 双括号可以进行逻辑运算,四则运算。
- 双括号结构 扩展了
for
,while
,if
条件测试运算 - 支持多个表达式运算,各个表达式之间用
,
分开。
#!/bin/bash
num=1
((num++))
((num=num+1+2-3*4/5))
((num+=1+2-3*4/5))
# 打印 [0...9]
for((i=0;i<10;i++))
do
echo -e "$((i))\n"
done
# 如果 5 能被 2 整除则输出 true,反之输出 false
if ((5%2==0)) ; then
echo 'true'
else
echo 'false'