shell脚本编写进度条
Shell脚本,是一种为shell编写的脚本程序。shell编程和Java,Python和PHP编程类似,只要有一个可以编写代码的文本编辑器和一个可以解释并执行代码的解释器就可以了。
来看个简单的shell脚本:
touch一个myshell.sh,其中.sh是shell脚本的后缀
#!/bin/bash
echo "hello shell!"
在这里解释一下第一行,#! 是一个约定的标记,它告诉系统应该用什么解释器来执行这个脚本。后面的/bin/bash就是解释器了。
要执行这个shell脚本有两种方式:
第一种方式: shell会fork创建一个子进程并调用exec来执行这个脚本程序,而且exec有一种机制,如果要执行的是一个文本文件而且第一行给出了解释器,那么就直接用解释器程序的代码段直接替换当前进程然后开始执行,而这个文本文件被当做命令行参数传给解释器。
第二种方式: 第二种方式也就是将文本文件传给解释器做命令行参数来执行。
需要注意的是:执行某些命令,不一定要创建子进程!这些不需要创建子进程的命令,叫做shell的内置命令,由父bash亲自执行。例如:cd命令就是一个内置命令。
shell是弱类型语言,看看下面的例子:
#!/bin/bash
a=1
b=3.14
c="hello"
d='m'
echo $a
echo $b
echo $c
echo $d
来看看运行结果:
可以看到shell变量中可以放整型、浮点型、字符型、字符串等等很多东西,在这里需要强调的一点是:变量名和等号直接不能有空格,如果带了空格会被shell解释为命令和命令行参数。下面是shell变量的命名规则:
当使用一个变量或输出的时候需要在变量名前加 $ 符号,但一般变量赋值的时候不需要使用,也可以给变量名加上花括号{ },这样是为了方便解释器识别边界。
如果我们要对变量进行计算时,就需要用双圆括号(( )),双圆括号中的内容是类C的,如下:
#!/bin/bash
a=1
b=2
c=$((a+b))
echo ${a}
echo ${b}
echo ${c}
如果我们需要删除一个变量就需要用到unset命令:
#!/bin/bash
mystr="hello word"
echo $mystr
unset mystr
echo $mystr
被删除的变量内容会被清空,可以看到第二个echo语句输出了一个空串
被readonly修饰的变量时只读变量,不可以修改它的值,同样也不能被删除
#!/bin/bash
readonly mystr="hello word"
echo ${mystr}
mystr="this is string"
echo $mystr
unset mystr
echo $mystr
本地变量:局部变量在脚本或命令中定义,只存在于当前shell中,其他shell启动的程序不能访问
环境变量:所有的程序,包括shell启动的程序,都能访问环境变量,可以从父进程传给子进程,利用printenv命令可以查看当前shell的环境变量,如果利用export可以将本地变量导出为环境变量
shell变量:shell变量是由shell程序设置的特殊变量。shell变量中有一部分是环境变量,有一部分是局部变量,这些变量保证了shell的正常运行
直接上例子:
#!/bin/bash
read a #从标准输入读入
test $a -eq 100
echo $?
看最后一条语句,echo $? 是查看上面最近一个程序的退出码,在shell脚本中,测试条件成立退出码为0,不成立为非0
除了上面的test还可以利用 [ ] 来进行测试:
注意:在使用 [ ] 的时候每个变量之间要有空格,变量和左右方括号之间也需要有空格,不然就会报错
#!/bin/bash
read a
[ $a -eq 100 ]
echo $?
从上面的例子可以注意到,我们是利用 -eq 来进行比较的,对于不同的类型,测试选项也不同
比较字符串的时候==和=都可以用来判断是不是相等,-z是用来判断一个字符串是否为空串,-n是判断一个字符串是否为非空串。
-d 判断是否为目录;-f 判断是否为普通文件;-b 是否为块设备;-c 是否为字符设备,来看例子:
#!/bin/bash
[ -d / ] #是否为目录
echo $?
[ -c /dev/tty ] #是否为块设备
echo $?
[ -b /dev/sda ] #是否为字符设备
echo $?
[ -f ./myshell.sh ] #是否为普通设备
echo $?
例子:
#!/bin/bash
myint=100
#判断myshell.sh是不是普通文件而且myint是否等于200
[ -f ./myshell.sh -a $myint -eq 200 ]
echo $?
#判断myint是否不等于200并取反
[ ! $myint -ne 200 ]
echo $?
#判断myint是否等于100或者myshell.sh是否是普通文件
[ $myint -eq 100 -o -f ./myshell.sh ]
echo $?
shell脚本的条件语句格式如下:
1.单分支判断语句
if 条件
then
条件成立执行的语句
fi
2.双分支判断语句
if 条件
then
条件成立执行的语句
else
条件不成立执行的语句
fi
3.多分支判断语句
if 条件1;then
条件1成立执行的语句
elif 条件2;then
条件2成立执行的语句
else
条件都不成功执行的语句
fi
来总结一下,shell脚本的条件判断语句是用 if、then、elif、else、fi 这几条命令来实现的,和C语言很类似,但要注意的是后面一定要有fi,shell脚本中控制分支结构结束都要和开头的单词相反,例如,if <–> fi,case <–> esac
还有一点就是如果两条命令写在同一行则需要用 ; 号隔开,一行只写一条命令就不需要写分号了。另外,then后面有换行,但这条命令没写完Shell会自动续行,把下一行接在then后面当作一条命令处理。和 [ 命令一样要注意命令和各参数之间必须用空格隔开
在这里直接上一个多分支的例子:
#!/bin/bash
read data
if [ $data -eq 100 ];then
echo "this is 100"
elif [ $data -eq 200 ]
then
echo "this is 200"
else
echo "hello word"
fi
在C语言中如果我们在if中什么都不做就可以写一条空语句 ; 或者什么都不写,但在shell脚本中如果出现空语句就会报错,所以在shell脚本中用 :这个空命令,这个命令什么事都不做,但它的退出码总是为真,在这里就不举例子了。
再补充一条:if命令的参数组成了一条子命令,如果该子命令的Exit Status为0(表示真),则执行then后面的子命令。如果Exit Status非 0(表示假),则执行elif、else或者fi后面的子命令。if后面的子命令通常是测试命令,除了 [ 和 test 命令,还可以放其他命令,只要该命令退出码为0,1来表明执行就可以
在C语言中有switch/case语句,在shell脚本中有case命令和它的功能是类似的,直接看个例子吧:
#!/bin/bash
read data
case $data in
"100" )
echo "this is 100"
;;
"200" )
echo "this is 200"
;;
"300" )
echo "this is 300"
;;
* )
echo "default"
;;
esac
C语言的case只能匹配整型或字符型常量表达式,而Shell脚本的case可以匹配字符串和通配符,在匹配完成要在后面加一个 ) ,每个匹配分支可以有若干条命令,最后必须以;;结束,就类似与C语言中的break。而代码中最后一行的 * 就相当于C语言中的default一样。
while循环只要while语句为真就执行
while 条件
do
语句
done
上例子:
#!/bin/bash
i=$1
while [ $i -lt 5 ]
do
echo "this is $i"
# ((i++))
let i++
done
看程序中,我们对循环变量做改变的时候,用了两种方式,其中一种是最开始说的双圆括号,还有一种是可以利用 let 命令
shell脚本对for循环有两种:
(1) 类C的写法
同样是利用我们上面的双圆括号,不多做解释了
#!/bin/bash
i=0
for ((i=0;i<10;i++))
do
echo "hello $i"
done
#!/bin/bash
for i in {a..c}{1..3}
do
echo "hello $i"
done
#!/bin/bash
for i in {a,b,c} {1,2,3}
do
echo "hello $i"
done
可以看到这两段代码的区别就是,第二段代码的两个花括号之间有一个空格,第一个不带空格的是将两个花括号中的内容进行排列组合,而不带空格的话是分别遍历两个花括号中的内容。当然也可以只有一个花括号,花括号中的内容可以像第二个一样枚举出来,也可以类似第一个直接利用 . .
shell还有一种自己特有的循环是until循环
until循环和while循环的写法很像,但是until循环是当条件为假就执行循环体
#!/bin/bash
i=0
until [ $i -ge 10 ]
do
echo "hello $i"
let i++
done
看看shell函数的格式:
[function] funcName()
{
语句
[return 返回值]
}
shell的函数没有参数列表,[ ]中的内容是可选的,function标识这是一个函数,后面跟函数名。也可以不加function直接写出函数名。shell函数的返回值也是可选的,只能返回整数,如果没有给出return,则默认返回最后一条语句的执行结果
#!/bin/bash
function myfun()
{
echo "this is a function!"
return 1
}
myfun
shell在定义函数时并不执行函数体中的命令,就像定义变量一样,只是给myfun这个名字一个定义, 到后面调用 myfun函数的时候才执行函数体中的命令。shell脚本中调用函数不用带括号,而且shell函数必须先定义再调用
shell函数虽然没有参数列表,但是依然可以给它传参。来看看下面的例子:
#!/bin/bash
function myfun()
{
echo "this is function"
echo $0
echo $1
echo $2
echo $#
echo $@
echo "this is function!"
}
myfun str1 str2
shell在调用函数的时候可以在函数后面跟上参数,在函数体内部就可以利用之前说过的获取命令行参数的方法来拿到函数参数
解释一下这些变量: