判断语句if…then形式
- 类似于
C/C++
中的if-else
语句。
单层if
- 命令格式:
if conditionthen 语句1 语句2 ...fi
- 示例:
a=3b=4if [ "$a" -lt "$b" ] && [ "$a" -gt 2 ]then echo ${a}在范围内fi
- 输出结果:
3在范围内
单层if-else
- 命令格式
if conditionthen 语句1 语句2 ...else 语句1 语句2 ...fi
- 示例:
a=3b=4if ! [ "$a" -lt "$b" ]then echo ${a}不小于${b}else echo ${a}小于${b}fi
- 输出结果:
3小于4
多层if-elif-elif-else
- 命令格式
if conditionthen 语句1 语句2 ...elif conditionthen 语句1 语句2 ...elif conditionthen 语句1 语句2else 语句1 语句2 ...fi
- 示例:
a=4if [ $a -eq 1 ]then echo ${a}等于1elif [ $a -eq 2 ]then echo ${a}等于2elif [ $a -eq 3 ]then echo ${a}等于3else echo 其他fi
- 输出结果:
其他
case…esac形式
类似于
C/C++
中的switch
语句。命令格式
case $变量名称 in 值1) 语句1 语句2 ... ;; # 类似于C/C++中的break 值2) 语句1 语句2 ... ;; *) # 类似于C/C++中的default 语句1 语句2 ... ;;esac
- 示例:
a=4case $a in 1) echo ${a}等于1 ;; 2) echo ${a}等于2 ;; 3) echo ${a}等于3 ;; *) echo 其他 ;;esac
- 输出结果:
其他
循环语句for…in…do…done
- 命令格式:
for var in val1 val2 val3do 语句1 语句2 ...done
- 示例1,输出a 2 cc,每个元素一行:
for i in a 2 ccdo echo $idone
- 示例2,输出当前路径下的所有文件名,每个文件名一行:
for file in `ls`do echo $filedone
- 示例3,输出1-10
for i in $(seq 1 10)do echo $idone
- 示例4,使用{1..10} 或者
for i in {a..z}do echo $idone
for ((…;…;…)) do…done
- 命令格式:
for ((expression; condition; expression))do 语句1 语句2done
- 示例,输出1-10,每个数占一行:
for ((i=1; i<=10; i++))do echo $idone
while…do…done循环
- 命令格式:
while conditiondo 语句1 语句2 ...done
- 示例,文件结束符为Ctrl+d,输入文件结束符后read指令返回false。
while read namedo echo $namedone
until…do…done循环
当条件为真时结束。
命令格式:
until conditiondo 语句1 语句2 ...done
- 示例,当用户输入yes或者YES时结束,否则一直等待读入。
until [ "${word}" == "yes" ] || [ "${word}" == "YES" ]do read -p "Please input yes/YES to stop this program: " worddone
break命令
跳出当前一层循环,注意与C/C++不同的是:break不能跳出case语句。
示例
while read namedo for ((i=1;i<=10;i++)) do case $i in 8) break ;; *) echo $i ;; esac donedone
- 该示例每读入非EOF的字符串,会输出一遍1-7。
- 该程序可以输入Ctrl+d文件结束符来结束,也可以直接用Ctrl+c杀掉该进程。
continue命令
跳出当前循环。
示例:
for ((i=1;i<=10;i++))do if [ `expr $i % 2` -eq 0 ] then continue fi echo $idone
- 该程序输出1-10中的所有奇数。
死循环的处理方式
如果AC Terminal可以打开该程序,则输入Ctrl+c即可。
否则可以直接关闭进程:
- 使用top命令找到进程的PID
- ps aux返回当前打开的所有进程
- 输入kill -9 PID即可关掉此进程
函数概述
bash中的函数类似于C/C++中的函数,但return的返回值与C/C++不同,返回的是exit code,取值为0-255,0表示正常结束。
如果想获取函数的输出结果,可以通过echo输出到stdout中,然后通过$(function_name)来获取stdout中的结果。
函数的return值可以通过$?来获取。
命令格式:
[function] func_name() { # function关键字可以省略 语句1 语句2 ...}
不获取 return值和stdout值
- 示例
func() { name=yxc echo "Hello $name"}func
- 输出结果:
Hello yxc
获取 return值和stdout值
不写return时,默认return 0。
示例
func() { name=yxc echo "Hello $name" return 123}output=$(func)ret=$?echo "output = $output"echo "return = $ret"
- 输出结果:
output = Hello yxcreturn = 123
函数的输入参数
在函数内,$1表示第一个输入参数,$2表示第二个输入参数,依此类推。
注意:函数内的$0仍然是文件名,而不是函数名。
示例:
func() { # 递归计算 $1 + ($1 - 1) + ($1 - 2) + ... + 0 word="" while [ "${word}" != 'y' ] && [ "${word}" != 'n' ] do read -p "要进入func($1)函数吗?请输入y/n:" word done if [ "$word" == 'n' ] then echo 0 return 0 fi if [ $1 -le 0 ] then echo 0 return 0 fi# $()会读取函数的stdout而不直接输出出来 sum=$(func $(expr $1 - 1))# 只在最后一层输出函数的stdout echo $(expr $sum + $1)}echo $(func 10)
- 输出结果:
55
函数内的局部变量
可以在函数内定义局部变量,作用范围仅在当前函数内。
可以在递归函数中定义局部变量。
命令格式:
local 变量名=变量值
- 例如:
#! /bin/bashfunc() { local name=yxc echo $name}funcecho $name
- 输出结果:
yxc
- 第一行为函数内的name变量,第二行为函数外调用name变量,会发现此时该变量不存在。
exit命令
exit命令用来退出当前shell进程,并返回一个退出状态;使用$?可以接收这个退出状态。
- return和exit的共同之处都是返回exit code
- 区别是return结束当前函数,exit结束整个shell脚本
exit命令可以接受一个整数值作为参数,代表退出状态。如果不指定,默认状态值是 0。
exit退出状态只能是一个介于 0~255 之间的整数,其中只有 0 表示成功,其它值都表示失败。
示例:
创建脚本test.sh,内容如下:
#! /bin/bashif [ $# -ne 1 ] # 如果传入参数个数等于1,则正常退出;否则非正常退出。then echo "arguments not valid" exit 1else echo "arguments valid" exit 0fi
- 执行该脚本:
acs@9e0ebfcd82d7:~$ chmod +x test.shacs@9e0ebfcd82d7:~$ ./test.sh acwingarguments validacs@9e0ebfcd82d7:~$ echo $? # 传入一个参数,则正常退出,exit code为00acs@9e0ebfcd82d7:~$ ./test.sharguments not validacs@9e0ebfcd82d7:~$ echo $? # 传入参数个数不是1,则非正常退出,exit code为11
文件重定向概述
每个进程默认打开3个文件描述符:
- stdin标准输入,从命令行读取数据,文件描述符为0
- stdout标准输出,向命令行输出数据,文件描述符为1
- stderr标准错误输出,向命令行输出数据,文件描述符为2
可以用文件重定向将这三个文件重定向到其他文件中。
重定向命令列表
命令 | 说明 |
---|---|
command > file | 将stdout重定向到file中 |
command < file | 将stdin重定向到file中 |
command >> file | 将stdout以追加方式重定向到file中 |
command n> file | 将文件描述符n重定向到file中 |
command n>> file | 将文件描述符n以追加方式重定向到file中 |
输入和输出重定向
# ls -l > 文件 (列表的内容写入文件a.txt中 覆盖写)# ls -al >> 文件 (列表的内容文件追加到文件aa.txt的末尾)# cat 文件1 > 文件2 (将文件1的内容覆盖到文件2)# echo "内容" >> 文件 (将echo的内容追加到文件末尾)echo -e "Hello \c" > output.txt # 将stdout重定向到output.txt中echo "World" >> output.txt # 将字符串追加到output.txt中read str < output.txt # 从output.txt中读取字符串echo $str # 输出结果:Hello World
同时重定向stdin和stdout
- 创建bash脚本:
#! /bin/bashread aread becho $(expr "$a" + "$b")
- 创建input.txt,里面的内容为:
34
- 执行命令:
acs@9e0ebfcd82d7:~$ chmod +x test.sh # 添加可执行权限acs@9e0ebfcd82d7:~$ ./test.sh output.txt # 从input.txt中读取内容,将输出写入output.txt中acs@9e0ebfcd82d7:~$ cat output.txt # 查看output.txt中的内容7
引入外部脚本概述
类似于C/C++中的include操作,bash也可以引入其他文件中的代码。
语法格式:
. filename # 注意点和文件名之间有一个空格或source filename# 引入的文件可以添加路径,比如使用绝对路径source /home/acs/test1.sh
示例
- 创建test1.sh,内容为:
#! /bin/bashname=yxc # 定义变量name
- 然后创建test2.sh,内容为:
#! /bin/bashsource test1.sh # 或 . test1.shecho My name is: $name # 可以使用test1.sh中的变量
- 执行命令:
acs@9e0ebfcd82d7:~$ chmod +x test2.shacs@9e0ebfcd82d7:~$ ./test2.shMy name is: yxc