Note about Shell script

this is my learning note
这是我的学习笔记

数据类型

1
2
#!/bin/bash
echo "Hello World !"

#! 是一个约定的标记,它告诉系统这个脚本需要什么解释器来执行,即使用哪一种 Shell。使用readlink -f $(which sh)可查看系统默认sh是什么shell。

赋予脚本执行权限后,可直接运行,执行脚本时,若脚本在当前目录下,应该使用./my_test.sh而非my_test.sh,因为使用my_test.sh时,linux 系统会去 PATH 里寻找my_test.sh

变量

定义变量

变量定义

1
your_var="your value"

注意变量名和等号之间不能有空格。

变量可以被重新赋值:

1
2
your_var="your value"
your_var="your new value"

将变量定义为只读变量后,不允许重新赋值

1
2
3
your_var="your value"
readonly your_var
your_var="your new value"

执行上面的脚本内容将会报错: your_var: is read only

可使用unset删除变量

1
unset variable_name

变量类型:

  • 局部变量: 在脚本或命令中定义,紧在当前shell实例中有效
  • 环境变量: 所有程序中有效
  • shell变量: 由shell程序设置的特殊变量。(比如$0$?$$$#等)

使用变量

使用$取变量值,为了帮助解释器识别变量边界,可在变量外添加花括号

1
2
3
test="hello shell"
echo $test
echo ${test}

在构造与变量紧连的字符串时,花括号就能发挥其作用了:

1
2
3
your_name="liming"
fold_name="${your_name}-test-fold"
echo $fold_name

shell 字符串

单引号

  • 单引号中的变量是无效的,任何字符串都会原样输出
  • 单引号字符串中不能出现单个的单引号,包括转义后的单引号

双引号

  • 双引号中可以有变量
  • 双引号中可以有转义字符

测试脚本如下:

1
2
3
4
5
6
your_var="test var"
echo 'Hello,\n this is a $your_var'
echo "Hello,\n this is a $your_var"

echo "Hello,\n \"this is a $your_var"
echo 'Hello,\n \'this is a $your_var'

在vim中编辑脚本内容,可发现高亮提示如下

执行结果如下:

字符串拼接

字符串可直接拼接:

1
2
3
your_var="test var"
echo 'Hello,\n this is a '$your_var' !'
echo "Hello,\n this is a "$your_var" !"

获取字符串长度

1
2
your_var="test var"
echo ${#your_vat} # 输出8

提取子字符串

1
2
your_var="test var"
echo ${your_var:1:3} # 输出est

记实践中遇到的的Bad substitution

原因是:Ubuntu下的默认shell(/bin/sh)指向dash,而不是bash

所以需要指明调用bash执行脚本:

shell数组

shell数组定义

1
array_name=(value0 value1 value2 value3)


1
2
3
4
5
6
array_name=(
value0
value1
value2
value3
)

或单个定义:

1
2
3
array_name[0]=value0
array_name[1]=value1
array_name[2]=value2

shell数组读取

1
${array_name[index]}

使用@获取数组中所有元素:

1
${array_name[@]}

shell参数

使用$数字编号获取对应编号的输入参数,
参数编号从0开始,是输入命令的第一个,往往是命令文件

用于处理参数的特殊字符:

特殊字符 说明
$# 参数个数
$* 以一个字符串显示所有参数
$$ 脚本运行的当前进程ID号
$! 后台运行的最后一个进程的ID号
$@ 与$*相同,但是使用时加引号,并在引号中返回每个参数
$- 显示Shell使用的当前选项,与set命令功能相同。
$? 显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。可获取之前执行的函数的返回值

其中 $*$@的区别:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
echo "输出\$@: "$@
echo "遍历\$@"
for var in $@;
do
echo $var
done

echo "遍历\"\$@\""
for var in "$@";
do
echo $var
done

echo "输出\$*: "$*

echo "遍历\$*"
for var in $*;
do
echo $var
done

echo "遍历\"\$*\""
for var in "$*";
do
echo $var
done

结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
输出$@: 1 2 3 4
遍历$@
1
2
3
4
遍历"$@"
1
2
3
4
输出$*: 1 2 3 4
遍历$*
1
2
3
4
遍历"$*"
1 2 3 4

基本运算符

算术运算符

关系运算符

布尔运算符

逻辑运算符

字字符串运算符

文件测试运算符

命令

echo、printf、test

test

此命令用于检测某个条件是否成立

控制流

条件语句

if

1
2
3
4
5
6
7
if condition
then
command1
command2
...
commandN
fi

if else

1
2
3
4
5
6
7
8
9
10
11
if condition
then
command1
command2
...
commandN
else
commandA
commandB
...
fi

if else-if else

1
2
3
4
5
6
7
8
9
10
11
12
13
14
if condition
then
command1
command2
elif condition2
then
command3
...
commandN
else
commandA
commandB
...
fi

循环

for

1
2
3
4
5
6
for var in item1 item2 item3 ... itemN
do
command1
...
commandK
done

while

1
2
3
4
while condition
do
command
done

until

与while相反,执行直到条件为true

1
2
3
4
until condition
do
command
done

break

跳出循环

多选择

case

1
2
3
4
5
6
7
8
9
10
11
12
case 值 in 
模式1)
command1
...
commandN1
;;
模式2)
command2
...
commandN2
;;
esac

其中;;表示break,esac表示结束标记,esaccase反过来。

函数

1
2
3
4
5
[function] function_name [()]
{
action;
[return int;]
}

其中[]表示可选内容。
传参方式为调用时直接在function_name后以以空格分隔即可,和shell命令传参方式一样。
函数中参数的使用也和shell脚本使用参数的方式一致。

示例:

1
2
3
4
5
6
7
func(){
echo "第一个参数是"$1
echo "第二个参数是"$2
return $(($1 + $2))
}
func 2 5
echo "相加之和为 "$?" !"

函数返回值在调用函数后通过$?获取。
如果对函数使用$(func 2 5),获取到的是func中 echo的内容

结果:

1
2
3
第一个参数是2
第二个参数是5
相加之和为 7 !

输入输出重定向

文件包含

1
. file_name


1
source file_name

注意这里的file_name也需要是可执行的路径,如果在当前目录下,需要使用./file_name,当使用相对路径时,是以启动路径为准的,而非以脚本自身的路径为准的。

参考

菜鸟教程

Shell脚本编程30分钟入门