shell脚本
1.for循环
Shell脚本的for循环结构和C语言很不一样,它类似于某些编程语言的foreach循环
for循环有两种写法
(1)for i in {a..z}
do
echo $i
done
(2)类C方式
for(( i=0; i<100; i++ ))
do
echo $i
done
2.if条件判断
if命令的参数组成一条子命令,如果该子命令的Exit Status 为0(表示真),则执行then后面的子命令,如果Exit Status非0(表示假)则执行elif(shell中的else if用elif表示)、else或者fi后面的子命令。if后面的子命令通常是测试命令,但也可以是其他命令。shell脚本中没有{}括号,所以用fi表示if语句块的结束。
关于参数列表:
$0:相当于C语言main函数的argv[0]
$1、$2..: 这些称为位置参数,相当于C语言main函数的argv[1]、argv[2]..
$#:相当于C语言main的argc(注意,这里的#后面不表示注释
)
$@:表示参数列表“$1”“$2”..,例如可以在for循环中的in后面
$?:上一条命令的Exit Status
$$:当前shell的进程号
实例:求参数列表中的最大值、最小值
程序
[ $# -eq 0 ] && {
echo "Usage $0 data1 .. datan"
exit 1
}
max=$1
min=$1
for i in $@
do
if [ $max -lt $i ];then
max=$i
fi
if [ $min -gt $i ];then
main=$i
fi
done
echo "max=$max,min=$min"
2.while循环
书写方法
while [ 条件判断 ]
do
内容
done
3.函数
shell中的函数被当做一个程序或小脚本,
当函数传参时,$0永远不被使用。
shell函数定义中没有返回值也没有参数列表(函数体的左花括号和后面的命令之间必须有空格或换行,如果将最后一条命令和右花括号写在同一行,命令末尾必须有分号)
shell脚本中的函数调用不写括号
shell脚本中的函数必须先定义后调用,一般把函数调用都写在脚本的前面,把函数调用和其他命令写在脚本的最后(类似C语言中的main函数,这才是整个脚本实际开始执行命令的地方)
shell函数没有参数列表,但shell中的函数就像是迷你脚本,调用函数时可以传任意个函数,在函数内同样是用$1 $2等变量来提取参数,函数中的位置参数相当于函数的局部变量,改变这些变量并不会影响函数外的$1 $2等变量。函数中可以用return命令返回,如果return后面跟一个数字则表示函数的Exit Status
函数中定义的变量默认在本bash中全局有效,声明变量时加上local ,可使变量只在函数体内有效
Shell脚本函数支持递归
实例:1.函数实现求最大、最小值
myfunction()
{
max=$1
min=$1
for i in $@
do
if [ $max -lt $i ];then
max=$i
fi
if [ $min -gt $i ];then
min=$i
fi
done
echo "max=$max,min=$min"
}
myfunction $@
实例2.程序 .(){ . | . & }; .
一个后台运行的递归函数,其内部不断创建子进程
该程序可使电脑关机,且无法杀掉
.是一个函数名
set +x
从此条语句以下不打印执行过程,只打印执行结果
set -x
从此条语句后,打印执行结果和执行过程
4.数组
shell支持一维数组(不支持多维数组),并且不限制数组的大小。类似C语言,数组原酸的下标由0开始编号。获取数组中的元素要利用下标,下标可以是整数或算术表达式,其值应大于或等于0
定义数组:
在shell中,用括号来表示数组,数组元素用“空格”符号分隔开。定义数组的一般形式为:array_name=(value1...valuen)
可以不使用连续的下标,且下标的范围没有限制。
读取数组元素值的一般形式:${array_name[index]}
使用@或*可以获取数组中的所有元素:${array_name[*]}
实例:将a到z存入数组,且打印下标和内容
arr=()
j=0
for i in {a..z}
do
arr[$j]=$i
let j++
done
j=0
for i in ${arr[@]}
do
echo $i$j
#print "%s" "$i$j"
let j++
done
5.条件测试
命令test或[可以测试一个条件是否成立,如果测试结果为真,则该命令的Exit Status为0,如果测试结果为假,则命令的Exit Status为1(与C语言逻辑正好相反)
左方括号[是一个命令的名字,传给命令的各参数之间应该用空格隔开
判断整数
-eq 相等
-ne 不相等
-gt 大于
-ge 大于等于
-lt 小于
-le 小于等于
判断字符串
== 相等
!= 不相等
= 相等
判断字符串为空 [ -z "字符串" ]
判断字符串部位空 [ -n "字符串" ]
判断文件为目录 [ -d 文件名 ]
判断文件为普通文件 [ -f 文件名 ]
带与、或、非的测试命令
[ ! EXPR ]:EXPR可以是任意一种测试条件
[ EXPR1 -a EXPR2 ]:EXPR1、EXPR2可以是任意一种测试条件
[ EXPR1 -o EXPR2 ]:EXPR1、EXPR2可以是任意一种测试调价
6.:是一个特殊的命令,称为空命令,该命令不做任何事,但Exit Status总是真的
7.case/esac
case命令可类比C语言的switch/case语句,esac表示case语句块的结束。C语言的case只能匹配整形或字符型常量表达式,而shell脚本的case可以匹配字符串和Wildcard,每个匹配分支可以有若干条命令,末尾以;;结束,执行时找到第一个匹配的分支并执行相应的命令,然后直接跳到esac之后,不需要像C语言一样用break跳出
printf也是一条命令 格式 printf "打印内容" "$变量"
实例:斐波那契数列
(1)迭代的方法(方法一)
first=1
second=1
last=1
i=3
while [ $i -le $1 ]
do
let last=first+second
let first=second
let second=last
let i++
done
echo $last
(2)迭代方法实现(方法二)
arr=(1 1)
i=0
while [ $i -le $1 ]
do
let arr[$i+2]=arr[$i+1]+arr[$i]
let i++
done
echo ${arr[@]}
echo ${arr[$1-1]}
(3)递归方法实现
if [ $# -ne 1 ];then
exit 1
fi
function fib(){
local num=$1
if [ $num -le 2 ];then
echo 1
return
fi
local p=$((num-1))
local pp=$((num-2))
local first=`fib $pp`
local second=`fib $p`
echo "$first+$second" | bc
}
fib $1
(4)简化版本递归实现
function fib(){
local num=$1
[ $num -le 2 ] && {
echo 1
return
}
echo " `fib $((num-1))`+`fib $((num-2))`" | bc
实例:SHELL脚本读取文件,将文件内容按三个字符截取为一组,并且将小写字母转换成大写字母
读取文件方法 cat file | while read line
cut -c 按字符截取
大小写替换 echo "abc" | tr '[a-z]' '[A-Z]'
while read line
do
part1=`echo $line | cut -c 1-3`
part2=`echo $line | cut -c 4-6 | tr '[a-z]' '[A-Z]'`
part3=`echo $line | cut -c 7-9`
echo $part3$part2$part1 >> file.res
done < file
实例:脚本与信号关联
利用t
rap命令
function fun(){
echo "hello world"
return 0
}
trap 'fun' 2
while :
do
:
done
头文件引用方式,使用. 头文件文件名称或source 头文件名称或sh 头文件名称