Shell是一个命令解释器,它解释由用户输入的命令并且把它们送到内核,不仅如此,Shell有自己的编程语言用于对命令的编辑,它允许用户编写由shell命令组成的程序.Shel编程语言具有普通编程语言的很多特点,比如它也有循环结构和分支控制结构等,用这种编程语言编写的Shell程序与其他应用程序具有同样的效果,下面我们会介绍Shell-Script的编写.
文章声明 该系列文章部分文字描述,整理于以下文献,化繁为简. 《鸟哥的Linux私房菜 (基础学习篇 第三版)》 - 作者:鸟哥 《Linux就该这么学》 - 作者:刘遄
Shell 条件判断
◆按文件类型判断◆
1.使用 [] 来执行判断,并使用echo $? 判断执行结果
[ | ]|
lyshark.log passwd.awk | |
[ | ]|
[ | ]|
0 | |
[ | ]|
[ | ]|
1 |
2.我们可以结合之前所学的 && 和 || 实现判断后输出判断结果
[root@localhost ~]# ls | |
lyshark.log passwd.awk | |
[root@localhost ~]# [ -e ./lyshark.log ] && echo "check ok" || echo "None" | |
check ok | |
[root@localhost ~]# [ -e ./shar ] && echo "check on" || echo "None" | |
None |
◆按文件权限判断◆
1.使用 -r 判断文件是否可读,和可执行
[root@localhost ~]# ls | |
lyshark.log passwd.awk | |
[root@localhost ~]# [ -r ./lyshark.log ] && echo "check ok" || echo "None" | |
check ok | |
[root@localhost ~]# [ -x ./lyshark.log ] && echo "check ok" || echo "None" | |
None | |
[root@localhost ~]# [ -r ./lyshark.log ] && [ -x ./lyshark.log ] && echo "可读,可执行" || echo "可读,不可执行" || echo | |
"不可读,不可执行" | |
可读,不可执行 |
◆两文件之间的比较◆
1.通过 -ef 判断是否是相同的I节点
[root@localhost ~]# ls -li | |
total 0 | |
8409155 -rw-r--r-- 2 root root 0 Sep 25 21:39 lyshark_ln.log | |
8409155 -rw-r--r-- 2 root root 0 Sep 25 21:39 lyshark.log | |
[root@localhost ~]# [ ./lyshark.log -ef lyshark_ln.log ] && echo "ok" || echo "no" | |
ok |
◆数值之间的比较◆
1.比较两数字,大小关系
[root@localhost ~]# [ 23 -ge 24 ] && echo "23 >= 24 " || echo "23 <= 24" | |
23 <= 24 | |
[root@localhost ~]# [ 30 -ge 24 ] && echo "30 >= 24 " || echo "30 <= 24" | |
30 >= 24 |
◆字符串之间的比较◆
1.字符串之间的比较例子,字符串是否为空
[root@localhost ~]# name=LyShark | |
[root@localhost ~]# age="" | |
[root@localhost ~]# unset sex | |
[root@localhost ~]# [ -z "$name" ] && echo "字符串空" || echo "不为空" | |
不为空 | |
[root@localhost ~]# [ -z "$age" ] && echo "字符串空" || echo "不为空" | |
字符串空 | |
[root@localhost ~]# [ -z "$sex" ] && echo "字符串空" || echo "不为空" | |
字符串空 |
2.两个字符串相等比较
[root@localhost ~]# x=100 | |
[root@localhost ~]# y=200 | |
[root@localhost ~]# z=100 | |
[root@localhost ~]# [ "x" == "y" ] && echo "yes" || echo "no" | |
no | |
[root@localhost ~]# [ "$x" == "$y" ] && echo "yes" || echo "no" | |
no | |
[root@localhost ~]# [ "$x" == "$z" ] && echo "yes" || echo "no" | |
yes |
◆多重条件判断◆
1.逻辑与:判断变量x不为空,并且x大于20
[root@localhost ~]# declare -i x=10 | |
[root@localhost ~]# [ -n "$x" -a "$x" -gt 20 ] && echo "yes" || echo "no" | |
no | |
[root@localhost ~]# declare -i x=30 | |
[root@localhost ~]# [ -n "$x" -a "$x" -gt 20 ] && echo "yes" || echo "no" | |
yes |
2.逻辑非:判断x变量不为空,或!取反
[root@localhost ~]# declare -i x=30 | |
[root@localhost ~]# [ -n "$x" ] && echo "yes" || echo "no" | |
yes | |
[root@localhost ~]# [ ! -n "$x" ] && echo "yes" || echo "no" | |
no |
IF条件判断
if、then、else语句用于判断给定的条件是否满足,并根据测试条件的真假来选择相应的操作.if/else仅仅用于两分支判断,多分支的选择时需要用到if/else语句嵌套、if/elif/else和case多分支选择判断结构.
IF结构例子: 一个就简单的单分支结构.测试条件后如果没有";"则then语句要换行.
echo "Please input a Number:" | |
read Num | |
if [ "$Num" -lt 15 ] | |
then | |
echo "$Num <= 15" | |
fi |
IF/IF-ELSE结构: 一个双分支结构,如下执行删除文件,成功返回then是否返回else.
echo "Please input the file which you want to delete:" | |
read file | |
if rm -f "$file" | |
then | |
echo "Delete the file $file sucessfully!" | |
else | |
echo "Delete the file $file failed!" | |
fi |
IF/ELSE嵌套: 可同时判断三个或三个以上条件,但要注意if与else配对关系,else语句总是与它上面最近的未配对的if配对.
#提示用户输入分数(0-100) | |
echo "Please Input a integer(0-100): " | |
read score | |
#判断学生的分数类别 | |
if [ "$score" -lt 0 -o "$score" -gt 100 ] | |
then | |
echo "The score what you input is not integer or the score is not in (0-100)." | |
else | |
if [ "$score" -ge 90 ] | |
then | |
echo "The grade is A!" | |
else | |
if [ "$score" -ge 80 ] | |
then | |
echo "The grade is B!" | |
else | |
if [ "$score" -ge 70 ] | |
then | |
echo "The grade is C!" | |
else | |
if [ "$score" -ge 60 ] | |
then | |
echo "The grade is D!" | |
else | |
echo "The grade is E!" | |
fi | |
fi | |
fi | |
fi | |
fi |
IF/ELIF/ELSE结构: if/else嵌套在编程中很容易漏掉then或fi产生错误,而且可读性很差,因此引入if/elif/else结构针对某一事件的多种情况进行处理,fi只出现一次,可读性也提高了.
echo "Please Input a integer(0-100): " | |
read score | |
if [ "$score" -lt 0 -o "$score" -gt 100 ] | |
then | |
echo "The score what you input is not integer or the score is not in (0-100)." | |
elif [ "$score" -ge 90 ] | |
then | |
echo "The grade is A!" | |
elif [ "$score" -ge 80 ] | |
then | |
echo "The grade is B!" | |
elif [ "$score" -ge 70 ] | |
then | |
echo "The grade is C!" | |
elif [ "$score" -ge 60 ] | |
then | |
echo "The grade is D!" | |
else | |
echo "The grade is E!" | |
fi |
实例1: 通过单分支判断磁盘是否已满.
[root@localhost ~]# cat if.sh | |
#!/bin/bash | |
ret=$( df -h | grep "/dev/sda1" | awk '{printf $5}' | cut -d "%" -f 1 ) | |
if [ $ret -ge 80 ] | |
then | |
echo -e "/dev/sda1 is full !!" | |
fi |
实例2: 通过多分支判断磁盘是否已满.
[root@localhost ~]# cat if.sh | |
#!/bin/bash | |
ret=$( df -h | grep "/dev/sda1" | awk '{printf $5}' | cut -d "%" -f 1 ) | |
if [ $ret -ge 80 ] | |
then | |
echo -e "/dev/sda1 is full !" | |
else | |
echo -e "/dev/sda1 is not full !" | |
fi |
实例3: 多分支判断小例子.
[root@localhost ~]# cat if.sh | |
#!/bin/bash | |
read -p "输入一个数字:" num | |
if [ "$num" -gt "100" ] | |
then | |
echo -e "这个数大于100" | |
elif [ "$num" -lt "100" ] | |
then | |
echo -e "这个数小于100" | |
elif [ "$num" -eq "100" ] | |
then | |
echo -e "这个数等于100" | |
fi |
实例4: 判断输入的年份是否是润年(润年条件:1、能被4整除,但不能被100整除的年份.2、能被100整除,又能被400整除的年份)
echo "Please Input a year: " | |
read year | |
let "n1=$year % 4" | |
let "n2=$year % 100" | |
let "n3=$year % 400" | |
if [ "$n1" -ne 0 ] | |
then | |
leap=0 | |
elif [ "$n2" -ne 0 ] | |
then | |
leap=1 | |
elif [ "$n3" -ne 0 ] | |
then | |
leap=0 | |
else | |
leap=1 | |
fi |
CASE分支结构
case结构变量值依次比较,遇到双分号则跳到esac后的语句执行,没有匹配则脚本将执行默认值*
"后的命令,直到"';;"为止.case的匹配值必须是常量或正则表达式.
read -p "输入一个符号:" temp | |
case $temp in | |
"-print") | |
echo -e "您执行了print函数" | |
;; | |
"-save") | |
echo -e "您执行了save函数" | |
;; | |
"-help") | |
echo -e "您执行了help函数" | |
;; | |
*) | |
echo -e "您执行了其他操作" | |
;; | |
esac |
FOR循环结构
Shell编程中循环命令用于特定条件下决定某些语句重复执行的控制方式,有三种常用的循环语句:for、while和until.while循环和for循环属于"当型循环",而until属于"直到型循环",循环控制符:break和continue控制流程转向.
列表FOR循环: 循环打印数据分别从1遍历到5.
do和done之间的命令称为循环体,执行次数和list列表中常数或字符串的个数相同.for循环,首先将in后list列表的第一个常数或字符串赋值给循环变量,然后执行循环体,以此执行list,最后执行done命令后的命令序列.
for tmp in {1..5} | |
do | |
echo "Hello, Welcome $tmp times" | |
done |
FOR循环累加: 通过FOR循环累加打印数据.
通过i的按步数2不断递增,计算sum值为2500.同样可以使用seq命令实现按2递增来计算1~100内的所有奇数之和,for i in $(seq 1 2 100)
,seq表示起始数为1,跳跃的步数为2,结束条件值为100.
sum=0 | |
for i in {1..100..2} | |
do | |
let "sum+=i" | |
done | |
echo "sum=$sum" |
FOR循环遍历目录: 通过for循环显示当前目录下所有的文件.
for file in $( ls ) | |
#for file in * | |
do | |
echo "file: $file" | |
done |
不带列表FOR: 由用户制定参数和参数的个数,与上述的for循环列表参数功能相同.
echo "number of arguments is $#" | |
echo "What you input is: " | |
for argument | |
do | |
echo "$argument" | |
done |
C风格FOR循环: 也被称为计次循环.
for((integer = 1; integer <= 5; integer++)) | |
do | |
echo "$integer" | |
done |
实例1: 通过for循环打印1-10.
[root@localhost ~]# cat for.sh | |
#!/bin/bash | |
for temp in `seq 1 10` | |
do | |
echo -e "打印数据: $temp" | |
done |
实例2: 通过for循环计算1-100的累加和.
[root@localhost ~]# cat for.sh | |
#!/bin/bash | |
declare -i sum=0 | |
for temp in `seq 1 100` | |
do | |
sum=$sum+$temp | |
done | |
echo -e "从1+到100的结果是: $sum" |
实例3: 从列表中选择数据.
[root@localhost ~]# cat for.sh | |
#!/bin/bash | |
for temp in 1 3 5 7 9 | |
do | |
echo -e "打印: $temp" | |
done | |
[root@localhost ~]# bash for.sh | |
打印: 1 | |
打印: 3 | |
打印: 5 | |
打印: 7 | |
打印: 9 |
实例4: 读取文件内容并打印.
[root@localhost ~]# cat for.sh | |
#!/bin/bash | |
world=`cat /etc/passwd` | |
for temp in $world | |
do | |
echo -e "打印: $temp" | |
done |
WHILE 循环
也称为前测试循环语句,重复次数是利用一个条件来控制是否继续重复执行这个语句.为了避免死循环,必须保证循环体中包含循环出口条件即表达式存在退出状态为非0的情况.
计数控制: 指定了循环的次数500,初始化计数器值为1,不断测试循环条件i是否小于等于100.在循环条件中设置了计数器加2来计算1~100内所有的奇数之和.
sum=0 | |
i=1 | |
while(( i <= 100 )) | |
do | |
let "sum+=i" | |
let "i += 2" | |
done | |
echo "sum=$sum" |
结束标记控制的while循环: 设置一个特殊的数据值(结束标记)来结束while循环.
echo "Please input the num(1-10) " | |
read num | |
while [[ "$num" != 4 ]] | |
do | |
if [ "$num" -lt 4 ] | |
then | |
echo "Too small. Try again!" | |
read num | |
elif [ "$num" -gt 4 ] | |
then | |
echo "To high. Try again" | |
read num | |
else | |
exit 0 | |
fi | |
done | |
echo "Congratulation, you are right! " |
标志控制的while循环: 使用用户输入的标志值来控制循环的结束(避免不知道循环结束标志的条件).
echo "Please input the num " | |
read num | |
sum=0 | |
i=1 | |
signal=0 | |
while [[ "$signal" -ne 1 ]] | |
do | |
if [ "$i" -eq "$num" ] | |
then | |
let "signal=1" | |
let "sum+=i" | |
echo "1+2+...+$num=$sum" | |
else | |
let "sum=sum+i" | |
let "i++" | |
fi | |
done |
命令行控制的while循环: 使用命令行来指定输出参数和参数个数,通常与shift结合使用,shift命令使位置变量下移一位(2代替1、3代替2,并使#变量递减),当最后一个参数显示给用户,#会等于0,
echo "number of arguments is $#" | |
echo "What you input is: " | |
while [[ "$*" != "" ]] | |
do | |
echo "$1" | |
shift | |
done |
while计算: 通过while循环,计算1-100的累加和.
[root@localhost ~]# cat while.sh | |
#!/bin/bash | |
declare -i x=0 | |
declare -i num=0 | |
while [ "$x" -lt "100" ] | |
do | |
x=$x+1 | |
num=$num+$x | |
done | |
echo -e "从1-100结果是: $num" | |
[root@localhost ~]# bash while.sh | |
从1-100结果是: 5050 |
UNTIL 循环
until命令和while命令类似,while能实现的脚本until同样也可以实现,但区别是until循环的退出状态是不为0,退出状态是为0(与while刚好相反),即whie循环在条件为真时继续执行循环而until则在条件为假时执行循环.
i=0 | |
until [[ "$i" -gt 5 ]] #大于5 | |
do | |
let "square=i*i" | |
echo "$i * $i = $square" | |
let "i++" | |
done | |
#!/bin/bash | |
for (( i = 1; i <=9; i++ )) | |
do | |
for (( j=1; j <= i; j++ )) | |
do | |
let "temp = i * j" | |
echo -n "$i*$j=$temp " | |
done | |
echo "" #output newline | |
done | |
#!/bin/bash | |
i=0 | |
until [[ "$i" -gt 5 ]] #大于5 | |
do | |
let "square=i*i" | |
echo "$i * $i = $square" | |
let "i++" | |
done |
跳出语句(break,continue)
break: 在for、while和until循环中break可强行退出循环,break语句仅能退出当前的循环,如果是两层循环嵌套,则需要在外层循环中使用break.
sum=0 | |
for (( i=1; i <= 100; i++)) | |
do | |
let "sum+=i" | |
if [ "$sum" -gt 1000 ] | |
then | |
echo "1+2+...+$i=$sum" | |
break | |
fi | |
done |
continue: 在for、while和until中用于让脚本跳过其后面的语句,执行下一次循环.continue用于显示100内能被7整除的数.
m=1 | |
for (( i=1; i < 100; i++ )) | |
do | |
let "temp1=i%7" #被7整除 | |
if [ "$temp1" -ne 0 ] | |
then | |
continue | |
fi | |
echo -n "$i " | |
let "temp2=m%7" #7个数字换一行 | |
if [ "$temp2" -eq 0 ] | |
then | |
echo "" | |
fi | |
let "m++" | |
done |
SELECT 语句
select结构从技术角度看不能算是循环结构,只是相似而已,它是bash的扩展结构用于交互式菜单显示,功能类似于case结构比case的交互性要好.
[root@localhost ~]# cat select.sh | |
#!/bin/bash | |
echo -e "请选择系统类型?" | |
select var in "Linux" "GNU HURD" "FreeBSD" "Other"; | |
do | |
if [ $var == "Linux" ] | |
then | |
echo -e "您的系统是Linux" | |
elif [ $var == "FreeBSD" ] | |
then | |
echo -e "您的系统是FreeBSD" | |
fi | |
break | |
done | |
[root@localhost ~]# bash select.sh | |
请选择系统类型? | |
1) Linux | |
2) GNU HURD | |
3) FreeBSD | |
4) Other | |
#? 1 | |
您的系统是Linux | |
#!/bin/bash | |
declare -a serial | |
serial=(1 2 3 4) | |
PS3="Enter a number: " | |
select var in "a" "b" "c" "d" | |
do | |
if ! echo ${serial[@]} | grep -q $REPLY | |
then | |
echo "please enter [1-4]." | |
continue | |
fi | |
echo "your anwser is: $var" | |
break | |
done | |
[root@localhost ~]# bash select.sh | |
1) a | |
2) b | |
3) c | |
4) d | |
Enter a number: 1 | |
your anwser is: a |
FUNCTION 函数
[root@localhost ~]# cat function.sh | |
#!/bin/bash | |
function my_print() | |
{ | |
echo -e "------------------------" | |
echo -e "hello world" | |
echo -e "------------------------" | |
return "127" | |
} | |
my_print | |
echo $? | |
[root@localhost ~]# bash function.sh | |
------------------------ | |
hello world | |
------------------------ | |
127 |
标准输入输出
标准输出: echo命令直接输出指定的字符串,或在Shell环境下直接打印字符串变量中的数据.
[root@localhost ~]# echo --help | |
语法格式:[ echo [选项] [输出内容] ] | |
-e #支持反斜线控制的字符转换 | |
-n #取消输出后行尾的换行符号 |
该命令的控制字符如下所示.
----------------------------------------------------------------------------------------- | |
\\ #输出\本身 | |
\a #输出警告音 | |
\b #退格键,也就是向左删除键 | |
\c #取消输出行末的换行符,和"-n"选项一致 | |
\e #ESCAPE键 | |
\f #换页符 | |
\n #换行符 | |
\r #回车键 | |
\t #制表符,也就是Tab键 | |
\v #垂直制表符 | |
\0nnn #按照八进制ASCII码输出字符,其中0为数字零,nnn是三位八进制数 | |
\xhh #按照十六进制ASCII码表输出字符,其中hh是两位十六进制数 | |
----------------------------------------------------------------------------------------- |
一些特殊的输出格式.
\\ #输出\本身 | |
"\e[1" #代表颜色输入开始 | |
"\e[0m" #代表颜色输入结束 | |
\e[0m #关闭所有属性 | |
\e[1m #设置高亮度 | |
\e[4m #下划线 | |
\e[5m #闪烁 | |
\e[7m #反显 | |
\e[8m #消隐 | |
\e[nA #光标上移n行 | |
\e[nB #光标下移n行 | |
\e[nC #光标右移n行 | |
\e[nD #光标左移n行 | |
\e[y;xH #设置光标位置 | |
\e[2J #清屏 | |
\e[K #清除从光标到行尾的内容 | |
\e[s #保存光标位置 | |
\e[u #恢复光标位置 | |
\e[25l #隐藏光标 | |
\e[25h #显示光标 | |
----------------------------------------------------------------------------------------- | |
文字颜色和底纹颜色: | |
文字颜色代码:30=黑色,31=红色,32=绿色,33=黄色,34=蓝色,35=洋红,36=青色,37=白色,39=结束 | |
底纹颜色代码:40=黑色,41=红色,42=绿色,43=黄色,44=蓝色,45=洋红,46=青色,47=白色,49=结束 | |
----------------------------------------------------------------------------------------- |
输出一个红字,并且黄底的"hello world"
[root@localhost ~] | |
hello world |
输出\a本身
[root@localhost ~]# echo -e "\\\a" | |
\a |
文本格式化: printf 文本格式化输出命令
[root@localhost ~]# printf --help | |
输出类型: | |
%ns: #输出字符串,n是数字,指代输出几个字符 | |
%ni: #输出证书,n是数字,指代输出几个数字 | |
%m.nf: #输出浮点数,m和n是数字,指代输出整数位和小数位 | |
输出格式: | |
\a: #输出警告音 | |
\b: #输出退格键,也就是Backspace键 | |
\f: #清屏 | |
\n: #换行符 | |
\r: #回车,也就是Enter键 | |
\t: #水平输出退格键,也就是Tab键 | |
\v: #垂直输出退格键,也就是Tab键 | |
#注意:print 和 printf 的主要区别在有 printf 是标准的格式化输出,必须手动指定换行和tab. |
在进行实验之前,首先创建一个文件,来做测试用
[root@localhost ~]# cat lyshark.log | |
ID NAME AGE Gender Mark | |
1 WR 22 m 100 | |
2 LC 26 m 90 | |
3 LY 23 m 88 | |
4 XDL 40 b 100 |
通过 printf
函数打印文本内容,如果不指定输出格式,则会把所有输出内容连在一起输出
[ | ]|
IDNAMEAGEGenderMark1WR22m1002LC26m903LY23m884XDL40b100 |
通过 printf
格式化后输出一段文本
[ | ]|
ID NAME AGE Gender Mark | |
1 WR 22 m 100 | |
2 LC 26 m 90 | |
3 LY 23 m 88 | |
4 XDL 40 b 100 |
通过 printf
按照整数型和浮点型输出,则需要修改
[ | ]|
1 WR 22.00 m 100 | |
2 LC 26.00 m 90 | |
3 LY 23.00 m 88 | |
4 XDL 40.00 b 100 |
标准输入: read命令从键盘读取变量的值,通常用在shell脚本中与用户进行交互的场合.
[root@localhost ~]# read --help | |
语法格式:[ read [选项] [输出内容] ] | |
-p #"提示信息",指定读取值时的提示符 | |
-t #指定读取值时等待的时间(秒),read等待的秒数 | |
-n #指定最多能接收的字符数(达到即执行) | |
-s #隐藏输入信息 |
通过Read命令读取一个值
[ | ]|
hello Lyshark | |
[ | ]|
hello Lyshark |
通过read命令读取,并输出一段提示信息,且10秒等待输入时间
[ | ]|
wangrui | |
[ | ]|
wangrui |
变量与运算符
基本的变量声明:
变量名称可以由字母、数字和下划线组成,但是不能以数字开头,变量中间不能有空格
[ | ]|
[ | ]|
lyshark | |
[ | ]|
-bash: 1name=lyshark: command not found |
在bash中变量的默认类型都是字符串型,如果要进行数值运算,则必修指定变量类型为数值型
[ | ]|
[ | ]|
[ | ]|
[ | ]|
10+20 |
变量用等号连接值,等号左右两侧不能有空格,如出现空格汇报错误
[ | ]|
[ | ]|
lyshark | |
[ | ]|
-bash: name: command not found | |
[ | ]|
[ | ]|
hello lyshark |
反引号引起来的会当作命令执行并返回结果,单引号则为输出字符串,反斜线为脱意字符
[root@localhost ~]# echo `date` | |
Sun Sep 23 23:51:38 EDT 2018 | |
[root@localhost ~]# echo "`date`" | |
Sun Sep 23 23:51:45 EDT 2018 | |
[root@localhost ~]# echo "$(date)" | |
Sun Sep 23 23:51:52 EDT 2018 | |
[root@localhost ~]# echo "\$(date)" | |
$(date) |
变量叠加:如果需要增加变量的值,那么可以进行变量值的叠加,叠加需要使用双引号包括.
[ | ]|
[ | ]|
[ | ]|
lyshark is | |
[ | ]|
[ | ]|
lyshark is hack | |
[ | ]|
[ | ]
参数传递:通过命令行传递参数,并打印这写参数的详细信息.
[root@localhost ~]# cat shell.sh | |
#!/bin/bash | |
echo -e "脚本名称:" $0 | |
echo -e "参数1:" $1 | |
echo -e "参数2: " $2 | |
echo -e "参数3: " $3 | |
echo -e "显示所有参数(作为一个整体显示): $*" | |
echo -e "显示所有参数(分页显示/分开接收): $@" | |
echo -e "显示参数个数: $#" | |
echo -e "实现计算器功能: $(($1$2$3))" | |
[root@localhost ~]# bash shell.sh 10 + 20 | |
脚本名称: shell.sh | |
参数1: 10 | |
参数2: + | |
参数3: 20 | |
显示所有参数(作为一个整体显示): 10 + 20 | |
显示所有参数(分页显示/分开接收): 10 + 20 | |
显示参数个数: 3 | |
实现计算器功能: 30 |
$?
判断上一条命令执行状态,成功返回0,失败返回非0
[ | ]|
[ | ]|
0 |
$$
返回自身进程号
[ | ]|
echo "本脚本的进程号是: $$" | |
[ | ]|
本脚本的进程号是: 1540 |
$!
返回最后一个后台执行的命令进程ID号
[ | ]|
find / -name "*.log" & | |
echo "最后一个后台执行的命令进程是: $!" | |
[ | ]|
最后一个后台执行的命令进程是: 1546 |
SHELL实现定义数组:
声明定义数组:
声明数组并定义元素,打印
[ | ]|
[ | ]|
[ | ]|
[ | ]|
hello world | |
[ | ]|
[ | ]|
hello world hello lyshark hello myblog | |
[ | ]|
3 | |
[ | ]|
3 | |
[ | ]|
declare -a name='([0]="hello world" [1]="hello lyshark" [2]="hello myblog")' | |
[ | ]|
[ | ]|
[ | ]|
5 | |
[ | ]|
declare -a num='([0]="1" [1]="2" [2]="3" [3]="4" [4]="5")' | |
[ | ]
定义初始化数组:
数组定义的多种方法(定义并初始化)
---------------------------------------------------------------------------------------------------- | |
[方法1] | |
[root~]# declare -a array_name=(Jerry Alice David LyShark) #通过命令行一部到位 | |
[root~]# declare -p array_name #打印查看结果 | |
declare -a array_name='([0]="Jerry" [1]="Alice" [2]="David" [3]="LyShark")' | |
---------------------------------------------------------------------------------------------------- | |
[方法2] | |
[root~]# declare -a array_name #先声明array_name数组 | |
[root~]# array_name=(Jerry Alice David LyShark) #紧接着打印 | |
[root~]# declare -p array_name | |
declare -a array_name='([0]="Jerry" [1]="Alice" [2]="David" [3]="LyShark")' | |
---------------------------------------------------------------------------------------------------- | |
[方法3] | |
[root~]# string="Jerry Alice Daid LyShark" #声明一个字符串 | |
[root~]# array_name=($string) #直接转换成数组 | |
[root~]# declare -p array_name | |
declare -a array_name='([0]="Jerry" [1]="Alice" [2]="Daid" [3]="LyShark")' | |
---------------------------------------------------------------------------------------------------- | |
[方法4] | |
[root~]# declare -a array_name #声明一个字符串 | |
[root~]# array_name=([0]="LyShark" [1]="Daid" [2]="Alice" [3]="Jerry") #直接转换成数组 | |
[root~]# echo ${array_name[@]} #查询数组元素 | |
LyShark Daid Alice Jerry | |
[root~]# declare -p array_name #命令行查询 | |
declare -a array_name='([0]="LyShark" [1]="Daid" [2]="Alice" [3]="Jerry")' | |
[root~]# unset array_name #使用结束,撤销数组 | |
---------------------------------------------------------------------------------------------------- |
求数组长度:
求数组长度,和单个数组元素长度.
[ | ]|
[ | ]|
Jerry Alice David LyShark | |
[ | ]|
4 | |
[ | ]|
4 | |
[ | ]|
5 | |
[ | ]|
7 | |
[ | ]
声明实现算数:
通过声明实现,整数计算
[ | ]|
[ | ]|
[ | ]|
[ | ]|
[ | ]|
[ | ]|
30 |
声明环境变量:
通过declare声明环境变量,和export是同样的效果
[root@localhost ~]# declare -x NAMES="LyShark" | |
[root@localhost ~]# env |grep NAMES | |
NAMES=LyShark | |
[root@localhost ~]# unset NAMES |
设置只读变量:
设置只读变量,只能读取变量,无法改变其数值
[ | ]|
[ | ]|
hello world | |
[ | ]|
-bash: test: readonly variable |
SHELL实现算数运算:
expr加法乘法运算:
使用expr完成一次加法和乘法运算,(运算符两边必须要有空格,否则不会运算)
[ | ]|
[ | ]|
[ | ]|
[ | ]|
30 | |
[ | ]|
[ | ]|
200 |
let加法乘法运算:
使用let完成一次加法与乘法运算,(此处并没有严格规定运算符两边的距离)
[root~]# declare -i x=100 | |
[root~]# declare -i y=200 | |
[root~]# let temp=$x+$y | |
[root~]# echo $temp | |
300 | |
[root~]# let temp=$x*$y | |
[root~]# echo $temp | |
20000 |
let ++ --:
let实现数值每次递增或递减1,类似C语言中的 x++
[ | ]|
[ | ]|
[ | ]|
2 | |
[ | ]|
[ | ]|
3 | |
[ | ]|
[ | ]|
2 | |
[ | ]|
[ | ]|
1 |
let x+=y:
let数值每次递增或递减x,类似C语言中的 x+=y
[ | ]|
[ | ]|
[ | ]|
2 | |
[ | ]|
[ | ]|
1 | |
[ | ]|
[ | ]|
11 |
特殊格式运算: 使用"
[ | ]|
[ | ]|
[ | ]|
[ | ]|
250 | |
[ | ]|
[ | ]|
15000 |
单行条件判断
按文件类型判断:
-b #判断文件是否为块设备 | |
-c #判断是否为字符设备文件 | |
-d #判断是否为目录文件 | |
-e #判断文件是否存在 | |
-f #判断是否为普通文件 | |
-L #判断是否为符号链接文件 | |
-p #判断是否为管道文件 | |
-s #判断文件是否为非空(非空为真) | |
-S #判断是否为套接字文件 |
使用-e
判断文件是否存在,返回0表示存在,非零为不存在,可以检测$?
来确定是否成功.
[ | ]|
[ | ]|
0 | |
[ | ]|
[ | ]|
1 |
除此之外,我们还可以结合之前所学的&&
和||
实现判断后输出判断结果.
[root@localhost ~]# [ -e /etc/passwd ] && echo "ok" || echo "no" | |
ok | |
[root@localhost ~]# [ -e /etc/lyshark ] && echo "ok" || echo "no" | |
no |
按文件权限判断:
-r #判断文件是否具有读权限 | |
-w #判断文件是否拥有写权限 | |
-x #判断文件是否拥有执行权限 | |
-u #判断文件是否具有SUID权限 | |
-g #判断文件是否具有SGID权限 | |
-k #判断文件是否具有SBIT权限 |
判断文件是否可读,且是否可被执行,如下:
[root@localhost ~]# [ -r /bin/bash ] && echo "ok" || echo "no" | |
ok | |
[root@localhost ~]# [ -r /bin/bash ] && [ -x /bin/bash ] && echo "ok" || echo "no" | |
ok |
两文件之间的比较:
file1 -nt file2 #判断文件1的修改时间是否比文件2新(如果新则返回真) | |
file1 -ot file2 #判断文件1的修改时间是否比文件2旧(如果旧则返回真) | |
file1 -ef file2 #判断文件1是否和文件2的I节点是否一致,两文件是否为同一个文件. |
通过使用-ef
判断两个文件是否拥有同一个I节点号.
[root@localhost ~]# ls -li | |
total 0 | |
8409155 -rw-r--r-- 2 root root 0 Sep 25 21:39 lyshark_ln.log | |
8409155 -rw-r--r-- 2 root root 0 Sep 25 21:39 lyshark.log | |
[root@localhost ~]# [ ./lyshark.log -ef lyshark_ln.log ] && echo "ok" || echo "no" | |
ok |
数值之间的比较:
number1 -eq number2 #判断number1是否等于number2 | |
number1 -ne number2 #判断number1是否不等于number2 | |
number1 -gt number2 #判断number1是否大于number2 | |
number1 -lt number2 #判断number1是否小于number2 | |
number1 -ge number2 #判断number1是否大于等于number2 | |
number1 -le number2 #判断number1是否小于等于number2 |
比较两数字,大小关系
[root@localhost ~]# [ 23 -ge 24 ] && echo "23 >= 24 " || echo "23 <= 24" | |
23 <= 24 | |
[root@localhost ~]# [ 30 -ge 24 ] && echo "30 >= 24 " || echo "30 <= 24" | |
30 >= 24 |
字符串之间比较:
-z string | |
-n string | |
string1 == string2 | |
string1 != string2 |
字符串之间的比较例子,字符串是否为空
[root@localhost ~]# name=LyShark | |
[root@localhost ~]# age="" | |
[root@localhost ~]# unset sex | |
[root@localhost ~]# [ -z "$name" ] && echo "字符串空" || echo "不为空" | |
不为空 | |
[root@localhost ~]# [ -z "$age" ] && echo "字符串空" || echo "不为空" | |
字符串空 | |
[root@localhost ~]# [ -z "$sex" ] && echo "字符串空" || echo "不为空" | |
字符串空 |
两个字符串相等比较
[root@localhost ~]# x=100 | |
[root@localhost ~]# y=200 | |
[root@localhost ~]# z=100 | |
[root@localhost ~]# [ "x" == "y" ] && echo "yes" || echo "no" | |
no | |
[root@localhost ~]# [ "$x" == "$y" ] && echo "yes" || echo "no" | |
no | |
[root@localhost ~]# [ "$x" == "$z" ] && echo "yes" || echo "no" | |
yes |
多重条件判断:
逻辑与:判断变量x不为空,并且x大于20
[root@localhost ~]# declare -i x=10 | |
[root@localhost ~]# [ -n "$x" -a "$x" -gt 20 ] && echo "yes" || echo "no" | |
no | |
[root@localhost ~]# declare -i x=30 | |
[root@localhost ~]# [ -n "$x" -a "$x" -gt 20 ] && echo "yes" || echo "no" | |
yes |
逻辑非:判断x变量不为空,或!取反
[root@localhost ~]# declare -i x=30 | |
[root@localhost ~]# [ -n "$x" ] && echo "yes" || echo "no" | |
yes | |
[root@localhost ~]# [ ! -n "$x" ] && echo "yes" || echo "no" | |
no |
IF条件判断
IF结构例子: 一个就简单的单分支结构.测试条件后如果没有";"则then语句要换行.
echo "Please input a Number:" | |
read Num | |
if [ "$Num" -lt 15 ] | |
then | |
echo "$Num <= 15" | |
fi |
IF/IF-ELSE结构: 一个双分支结构,如下执行删除文件,成功返回then是否返回else.
echo "Please input the file which you want to delete:" | |
read file | |
if rm -f "$file" | |
then | |
echo "Delete the file $file sucessfully!" | |
else | |
echo "Delete the file $file failed!" | |
fi |
IF/ELSE嵌套: 可同时判断三个或三个以上条件,但要注意if与else配对关系,else语句总是与它上面最近的未配对的if配对.
#提示用户输入分数(0-100) | |
echo "Please Input a integer(0-100): " | |
read score | |
#判断学生的分数类别 | |
if [ "$score" -lt 0 -o "$score" -gt 100 ] | |
then | |
echo "The score what you input is not integer or the score is not in (0-100)." | |
else | |
if [ "$score" -ge 90 ] | |
then | |
echo "The grade is A!" | |
else | |
if [ "$score" -ge 80 ] | |
then | |
echo "The grade is B!" | |
else | |
if [ "$score" -ge 70 ] | |
then | |
echo "The grade is C!" | |
else | |
if [ "$score" -ge 60 ] | |
then | |
echo "The grade is D!" | |
else | |
echo "The grade is E!" | |
fi | |
fi | |
fi | |
fi | |
fi |
IF/ELIF/ELSE结构: if/else嵌套在编程中很容易漏掉then或fi产生错误,而且可读性很差,因此引入if/elif/else结构针对某一事件的多种情况进行处理,fi只出现一次,可读性也提高了.
echo "Please Input a integer(0-100): " | |
read score | |
if [ "$score" -lt 0 -o "$score" -gt 100 ] | |
then | |
echo "The score what you input is not integer or the score is not in (0-100)." | |
elif [ "$score" -ge 90 ] | |
then | |
echo "The grade is A!" | |
elif [ "$score" -ge 80 ] | |
then | |
echo "The grade is B!" | |
elif [ "$score" -ge 70 ] | |
then | |
echo "The grade is C!" | |
elif [ "$score" -ge 60 ] | |
then | |
echo "The grade is D!" | |
else | |
echo "The grade is E!" | |
fi |
分支语句实现
read -p "输入一个符号:" temp | |
case $temp in | |
"-print") | |
echo -e "您执行了print函数" | |
;; | |
"-save") | |
echo -e "您执行了save函数" | |
;; | |
"-help") | |
echo -e "您执行了help函数" | |
;; | |
*) | |
echo -e "您执行了其他操作" | |
;; | |
esac | |
[root@localhost ~]# cat select.sh | |
#!/bin/bash | |
echo -e "请选择系统类型?" | |
select var in "Linux" "GNU HURD" "FreeBSD" "Other"; | |
do | |
if [ $var == "Linux" ] | |
then | |
echo -e "您的系统是Linux" | |
elif [ $var == "FreeBSD" ] | |
then | |
echo -e "您的系统是FreeBSD" | |
fi | |
break | |
done | |
[root@localhost ~]# bash select.sh | |
请选择系统类型? | |
1) Linux | |
2) GNU HURD | |
3) FreeBSD | |
4) Other | |
#? 1 | |
您的系统是Linux | |
#!/bin/bash | |
declare -a serial | |
serial=(1 2 3 4) | |
PS3="Enter a number: " | |
select var in "a" "b" "c" "d" | |
do | |
if ! echo ${serial[@]} | grep -q $REPLY | |
then | |
echo "please enter [1-4]." | |
continue | |
fi | |
echo "your anwser is: $var" | |
break | |
done | |
[root@localhost ~]# bash select.sh | |
1) a | |
2) b | |
3) c | |
4) d | |
Enter a number: 1 | |
your anwser is: a |
FOR循环结构
列表FOR循环: 循环打印数据分别从1遍历到5.
do和done之间的命令称为循环体,执行次数和list列表中常数或字符串的个数相同.for循环,首先将in后list列表的第一个常数或字符串赋值给循环变量,然后执行循环体,以此执行list,最后执行done命令后的命令序列.
for tmp in {1..5} | |
do | |
echo "Hello, Welcome $tmp times" | |
done |
FOR循环累加: 通过FOR循环累加打印数据.
通过i的按步数2不断递增,计算sum值为2500.同样可以使用seq命令实现按2递增来计算1~100内的所有奇数之和,for i in $(seq 1 2 100)
,seq表示起始数为1,跳跃的步数为2,结束条件值为100.
sum=0 | |
for i in {1..100..2} | |
do | |
let "sum+=i" | |
done | |
echo "sum=$sum" |
FOR循环遍历目录: 通过for循环显示当前目录下所有的文件.
for file in $( ls ) | |
#for file in * | |
do | |
echo "file: $file" | |
done |
不带列表FOR: 由用户制定参数和参数的个数,与上述的for循环列表参数功能相同.
echo "number of arguments is $#" | |
echo "What you input is: " | |
for argument | |
do | |
echo "$argument" | |
done |
C风格FOR循环: 也被称为计次循环.
for((integer = 1; integer <= 5; integer++)) | |
do | |
echo "$integer" | |
done |
实例1: 通过for循环打印1-10.
[root@localhost ~]# cat for.sh | |
#!/bin/bash | |
for temp in `seq 1 10` | |
do | |
echo -e "打印数据: $temp" | |
done |
实例2: 通过for循环计算1-100的累加和.
[root@localhost ~]# cat for.sh | |
#!/bin/bash | |
declare -i sum=0 | |
for temp in `seq 1 100` | |
do | |
sum=$sum+$temp | |
done | |
echo -e "从1+到100的结果是: $sum" |
实例3: 从列表中选择数据.
[root@localhost ~]# cat for.sh | |
#!/bin/bash | |
for temp in 1 3 5 7 9 | |
do | |
echo -e "打印: $temp" | |
done | |
[root@localhost ~]# bash for.sh | |
打印: 1 | |
打印: 3 | |
打印: 5 | |
打印: 7 | |
打印: 9 |
实例4: 读取文件内容并打印.
[root@localhost ~]# cat for.sh | |
#!/bin/bash | |
world=`cat /etc/passwd` | |
for temp in $world | |
do | |
echo -e "打印: $temp" | |
done |
WHILE 循环
计数控制: 指定了循环的次数500,初始化计数器值为1,不断测试循环条件i是否小于等于100.在循环条件中设置了计数器加2来计算1~100内所有的奇数之和.
sum=0 | |
i=1 | |
while(( i <= 100 )) | |
do | |
let "sum+=i" | |
let "i += 2" | |
done | |
echo "sum=$sum" |
结束标记控制的while循环: 设置一个特殊的数据值(结束标记)来结束while循环.
echo "Please input the num(1-10) " | |
read num | |
while [[ "$num" != 4 ]] | |
do | |
if [ "$num" -lt 4 ] | |
then | |
echo "Too small. Try again!" | |
read num | |
elif [ "$num" -gt 4 ] | |
then | |
echo "To high. Try again" | |
read num | |
else | |
exit 0 | |
fi | |
done | |
echo "Congratulation, you are right! " |
标志控制的while循环: 使用用户输入的标志值来控制循环的结束(避免不知道循环结束标志的条件).
echo "Please input the num " | |
read num | |
sum=0 | |
i=1 | |
signal=0 | |
while [[ "$signal" -ne 1 ]] | |
do | |
if [ "$i" -eq "$num" ] | |
then | |
let "signal=1" | |
let "sum+=i" | |
echo "1+2+...+$num=$sum" | |
else | |
let "sum=sum+i" | |
let "i++" | |
fi | |
done |
命令行控制的while循环: 使用命令行来指定输出参数和参数个数,通常与shift结合使用,shift命令使位置变量下移一位(2代替1、3代替2,并使#变量递减),当最后一个参数显示给用户,#会等于0,
echo "number of arguments is $#" | |
echo "What you input is: " | |
while [[ "$*" != "" ]] | |
do | |
echo "$1" | |
shift | |
done |
while计算: 通过while循环,计算1-100的累加和.
[root@localhost ~]# cat while.sh | |
#!/bin/bash | |
declare -i x=0 | |
declare -i num=0 | |
while [ "$x" -lt "100" ] | |
do | |
x=$x+1 | |
num=$num+$x | |
done | |
echo -e "从1-100结果是: $num" | |
[root@localhost ~]# bash while.sh | |
从1-100结果是: 5050 |
Break跳出循环
break: 在for、while和until循环中break可强行退出循环,break语句仅能退出当前的循环,如果是两层循环嵌套,则需要在外层循环中使用break.
sum=0 | |
for (( i=1; i <= 100; i++)) | |
do | |
let "sum+=i" | |
if [ "$sum" -gt 1000 ] | |
then | |
echo "1+2+...+$i=$sum" | |
break | |
fi | |
done |
continue: 在for、while和until中用于让脚本跳过其后面的语句,执行下一次循环.continue用于显示100内能被7整除的数.
m=1 | |
for (( i=1; i < 100; i++ )) | |
do | |
let "temp1=i%7" #被7整除 | |
if [ "$temp1" -ne 0 ] | |
then | |
continue | |
fi | |
echo -n "$i " | |
let "temp2=m%7" #7个数字换一行 | |
if [ "$temp2" -eq 0 ] | |
then | |
echo "" | |
fi | |
let "m++" | |
done |
FUNCTION函数
实现一个无参数传递的函数.
[root@localhost ~]# cat function.sh | |
#!/bin/bash | |
function my_print() | |
{ | |
echo -e "------------------------" | |
echo -e "hello world" | |
echo -e "------------------------" | |
return "127" | |
} | |
my_print | |
echo $? | |
[root@localhost ~]# bash function.sh | |
------------------------ | |
hello world | |
------------------------ | |
127 |
简单实现参数的传递.
[root@localhost ~]# cat function.sh | |
#!/bin/bash | |
function my_print() | |
{ | |
echo "参数1:" $1 | |
echo "参数2:" $2 | |
echo "参数3:" $3 | |
} | |
test="1 2 3" | |
my_print ${test} | |
[root@localhost ~]# bash function.sh | |
参数1: 1 | |
参数2: 2 | |
参数3: 3 |