shell编程进阶
shell编程语句有循环语句,判断语句。首先来讲讲if判断语句
if语句
单分支if语句
if 判断条件 ;then
执行条件为真的操作
fi
例:
read -p "please input number : " num
if [ $num -gt 0 ];then
echo "$num greater then 0"
fi
[root@localhost ~]#./ss.sh
please input number : 2
2 greater then 0
执行的结果是2大于0 那么就能说明判断的条件成立,所以执行后续操作。
双分支if语句
if 判断条件 ; then
条件为真执行操作
else
条件为假执行操作
fi
例
read -p "please input number : " num
if [ $num -gt 0 ] ;then
echo "$num greater then 0"
else
echo "$num is not positive number or not a number"
fi
[root@localhost ~]#./ss.sh
please input number : 22
22 greater then 0
[root@localhost ~]#./ss.sh
please input number : xx
./ss.sh: line 9: [: xx: integer expression expected
xx is not positive number or not a number
事例中得出的结果可以看出,双分支的话如果条件不成立就执行else的语句
多分支if语句
if 判断条件1; then
如果条件成立执行此处代码
elif 判断条件2; then
如果条件成立执行此处代码
elif 判断条件3; then
如果条件成立执行此处代码
…
else
如果条件都不成立执行此处代码
fi
例
read -p "please input file : " file
if [ -f $file ] ;then
echo "$file is files"
elif [ -d $file ];then
echo "$file is derictory"
elif [ -b $file ];then
echo "$file is block file"
else
echo "$file is other file"
fi
[root@localhost ~]#./ss.sh
please input file : /dev/sda
/dev/sda is block file
[root@localhost ~]#./ss.sh
please input file : /root/ss.sh
/root/ss.sh is files
[root@localhost ~]#./ss.sh
please input file : /root
/root is derictory
[root@localhost ~]#./ss.sh
please input file : /dev/zero
/dev/zero is other file
[root@localhost ~]#
从例子中可以看出多分支语句执行的结果是只要一条执行为真即为真
循环语句
循环语句常用的三种 for , while , until
for语句
for 变量名 in 列表; do
循环体
done
例:
sum=0
for i in `seq 10`;do
let sum+=i -->循环执行sum的值等于加i
done
echo $sum
unset sum
unset i
[root@localhost ~]#./s.sh
55
例子中得出的结果是55。 当我们定义一个变量sum为0的时候去执行循环,定义i的变量从列表倒入,也就是1-10的数值,然后去执行循环体sum的值等于i的循环相加,然后得出总值55。
while语句
进入条件:当语句成立时
循环体: 要执行的代码
退出条件:当语句不成立时
例
sum=0
i=0
while [ $i -lt 11 ] ;do
let sum+=i -->循环执行sum的值等于加i
let i++ -->当i=0的时候 let i++ 就是0+1 然后继续执行下一次循环
done
echo $sum
unset sum
unset i
[root@localhost ~]#./s.sh
55
while的使用是条件成立进入循环,当条件不成立时即退出循环。
until语句
进入条件:当语句不成立时
循环体: 要执行的代码
退出条件:当语句成立时
例:
sum=0
i=0
until [ $i -eq 11 ] ;do -->循环进入的条件,当$i等于11的时候即退出循环的条件
let sum+=i -->循环执行sum的值等于加i
let i++ -->当i=0的时候 let i++ 就是0+1 然后继续执行下一次循环
done
echo $sum
unset sum
unset i
[root@localhost ~]#./s.sh
55
循环使用的另一种风格的语法
C语言风格的语法
#!/bin/bash
#
for ((sum=0,i=0;i<11;i++));do
let sum+=i
done
echo $sum
[root@localhost ~]#./s.sh
55
在双小括号内的语法含义是((控制变量初始化;条件判断表达式;控制变量的修正表达式))
也可以一条命令直接算出结束,无需编写脚本。
[root@localhost ~]#for ((sum=0,i=0;i<=10;i++));do let sum+=i ;done ;echo $sum
55
select 语法
select variable in list
do
循环体命令
done
例:
脚本代码:
#!/bin/bash
#
#
PS3="please choose your menu: " -->PS3——Shell脚本中使用select时的提示符
select menu in hanbao jiroujuan mianbao taocan;do
case $REPLY in
1)
echo "The price is \$10"
;;
2)
echo "The price is \$15"
;;
3)
echo "The price is \$20"
;;
4)
echo "The price is \$25"
;;
*)
echo "you input food store not have "
break
;;
esac
echo $REPLY
done
[root@localhost ~]#./select.sh
1) hanbao
2) jiroujuan
3) mianbao
4) taocan
please choose your menu: 1
The price is $10
1
please choose your menu: 2
The price is $15
2
please choose your menu: 3
The price is $20
3
please choose your menu: 4
The price is $25
4
please choose your menu: 5
you input food store not have
[root@localhost ~]#
select 循环主要用于创建菜单,按数字顺序排列的菜单项将显示在标准错误上,并显示 PS3 提示符,
等待用户输入
用户输入菜单列表中的某个数字,执行相应的命令
用户输入被保存在内置变量 REPLY 中
select 是个无限循环,因此要用 break 命令退出循环,或用 exit 命令终止脚本。也可以按 ctrl+c退出循环
trap捕捉信号
trap ‘触发指令’
信号自定义进程收到系统发出的指定信号后,将执行触发指令,而不会执行原操作
trap ”
信号忽略信号的操作
trap ‘-’
信号恢复原信号的操作
trap -p
列出自定义信号
trap -l
查看所有可捕捉的信号
[root@localhost ~]#trap -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP
6) SIGABRT 7) SIGBUS 8) SIGFPE 9) SIGKILL 10) SIGUSR1
11) SIGSEGV 12) SIGUSR2 13) SIGPIPE 14) SIGALRM 15) SIGTERM
16) SIGSTKFLT 17) SIGCHLD 18) SIGCONT 19) SIGSTOP 20) SIGTSTP
21) SIGTTIN 22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO 30) SIGPWR
31) SIGSYS 34) SIGRTMIN 35) SIGRTMIN+1 36) SIGRTMIN+2 37) SIGRTMIN+3
38) SIGRTMIN+4 39) SIGRTMIN+5 40) SIGRTMIN+6 41) SIGRTMIN+7 42) SIGRTMIN+8
43) SIGRTMIN+9 44) SIGRTMIN+10 45) SIGRTMIN+11 46) SIGRTMIN+12 47) SIGRTMIN+13
48) SIGRTMIN+14 49) SIGRTMIN+15 50) SIGRTMAX-14 51) SIGRTMAX-13 52) SIGRTMAX-12
53) SIGRTMAX-11 54) SIGRTMAX-10 55) SIGRTMAX-9 56) SIGRTMAX-8 57) SIGRTMAX-7
58) SIGRTMAX-6 59) SIGRTMAX-5 60) SIGRTMAX-4 61) SIGRTMAX-3 62) SIGRTMAX-2
63) SIGRTMAX-1 64) SIGRTMAX
信号详情
引用名称 默认动作 说明
SIGHUP 终止进程 终端线路挂断
SIGINT 终止进程 中断进程
SIGQUIT 建立CORE文件 终止进程,并且生成core文件
SIGILL 建立CORE文件 非法指令
SIGTRAP 建立CORE文件 跟踪自陷
SIGBUS 建立CORE文件 总线错误
SIGSEGV 建立CORE文件 段非法错误
SIGFPE 建立CORE文件 浮点异常
SIGIOT 建立CORE文件 执行I/O自陷
SIGKILL 终止进程 杀死进程
SIGPIPE 终止进程 向一个没有读进程的管道写数据
SIGALARM 终止进程 计时器到时
SIGTERM 终止进程 软件终止信号
SIGSTOP 停止进程 非终端来的停止信号
SIGTSTP 停止进程 终端来的停止信号
SIGCONT 忽略信号 继续执行一个停止的进程
SIGURG 忽略信号 I/O紧急信号
SIGIO 忽略信号 描述符上可以进行I/O
SIGCHLD 忽略信号 当子进程停止或退出时通知父进程
SIGTTOU 停止进程 后台进程写终端
SIGTTIN 停止进程 后台进程读终端
SIGXGPU 终止进程 CPU时限超时
SIGXFSZ 终止进程 文件长度过长
SIGWINCH 忽略信号 窗口大小发生变化
SIGPROF 终止进程 统计分布图用计时器到时
SIGUSR1 终止进程 用户定义信号1
SIGUSR2 终止进程 用户定义信号2
SIGVTALRM 终止进程 虚拟计时器到时
例:捕捉ctrl + c 的信号
[root@localhost ~]#vim trap.sh
1 #!/bin/bash
2 #
3 #
4 trap 'echo "ctrl + c input invalid"' int --> 捕捉ctrl + c的信号并显示ctrl +c invalid
5 trap -p --> 列出捕捉信号的操作
6 for ((i=0;i<10;i++));do
7 echo $i
8 sleep 1
9 done
10
11 trap '' int -->捕捉的ctrl + c 的信号忽略
12 trap -p
13 for ((i=10;i<20;i++));do
14 echo $i
15 sleep 1
16 done
17
18 trap '-' int -->捕捉的ctrl + c的信号还原
19 trap -p
20 for ((i=20;i<30;i++));do
21 echo $i
22 sleep 1
23 done
接下来我们运行命令然后按ctrl + c 看看捕捉到的信号是执行什么样的操作
[root@localhost ~]#./trap.sh
trap -- 'echo "ctrl + c input invalid"' SIGINT -->这里显示出了捕捉信号的操作内容 也就是脚本里 trap -p输出
0 的内容
1
^Cctrl + c input invalid -->当程序执行i < 10 的循环时 捕捉 ctrl + c 是无效的 捕捉到的信号打印出我
2 们附的值
3
^Cctrl + c input invalid
4
5
^Cctrl + c input invalid
6
7
^Cctrl + c input invalid
8
^Cctrl + c input invalid
9
trap -- '' SIGINT
10
^C11 --> 这里捕捉到ctrl + c的信号,因为我们没写需要怎么操作,所以就直接忽略了
^C12
^C13
14
^C15
16
17
^C18
19
20 --> 当执行到i<30的循环时 trap '-'恢复信号trap -p不显示操作信号
21
22
23
24 -->当我们运行ctrl + c 的时候因为执行到了i<30的循环了,trap '-' 表示的
^C 是恢复原信号,所以ctrl + c 之前是中断操作 现在执行了中断
[root@localhost ~]#
例:捕捉kill的信号
[root@localhost ~]#vim trap2.sh
1 #!/bin/bash
2 #
3 #
4
5 trap 'echo "press input invalid"' term -->我们定义捕捉到的kill信号直接输出进程输入无效的肉容
6 trap -p -->显示下我们捕捉的信号类型
7 for ((i=0;i<100;i++));do
8 echo $i
9 sleep 1
10 done
我们运行脚本然后再开启另一台终端运行killall trap2.sh的操作,以下是具体操作内容
1终端 2终端
[root@localhost ~]#./trap2.sh [root@localhost ~]#killall trap2.sh
trap -- 'echo "press input invalid"' SIGTERM [root@localhost ~]#killall trap2.sh
0 [root@localhost ~]#killall trap2.sh
1 [root@localhost ~]#killall trap2.sh
2
3
4
5
press input invalid -->当我们在2终端运行杀进程时,脚本捕捉到了killall的信
6 号直接输出我们指定的内容
7
press input invalid
8
press input invalid
9
press input invalid
10
11
12
13
^C
[root@localhost ~]#
有趣事例1:使用for 循环画国际象棋棋盘
1 #!/bin/bash
2 #
3 #
4 for ((i=1;i<=16;i++)) ;do
5 let m=$i%4
6 case $m in
7 1|2)
8 for ((j=1;j<=4;j++));do
9 echo -ne "\033[43m \033[0m"
10 echo -ne "\033[41m \033[0m"
11 done
12 ;;
13 0|3)
14 for ((k=1;k<=4;k++));do
15 echo -ne "\033[41m \033[0m"
16 echo -ne "\033[43m \033[0m"
17 done
18 ;;
19 esac
20 echo
21 done
语句的思路。首先循环i赋值,i初使值是1 循环16次。 然后为m赋值 m的值是i的值取4的模(也就是i/4取余) 然后进行case语句的使用,当m的值是 1或2的时候我们执行 j的循环,执行4次 打印4个空格的黄色和4个空格的红色 当m的值是0或3的时候 执行K的循环,执行4次 打印4个空格的红色和4个空格的黄色 。 当i的循环执行一次后用echo 进行打印一行继续执行循环,直到i的值为16为止。
运行脚本得出的结果是
有趣事例2 编写sd5后十位的数对应的数值 限 32767 范围内
[root@localhost ~]#vim mima.sh
1 #!/bin/bash
2 #
3 #
4 Var_1=efbaf275cd
5 Var_2=4be9c40b8b
6 Var_3=44b2395c46
7 Var_4=f8c8873ce0
8 Var_5=b902c16c8b
9 Var_6=ad865d2f63
10 for ((i=0;i<=32767;i++));do
11 num=`echo $i |md5sum|cut -c1-10`
12 case $num in
13
14 $Var_1)
15 echo " $Var_1=$i "
16 ;;
17 $Var_2)
18 echo " $Var_6=$i "
19 ;;
20 $Var_3)
21 echo " $Var_6=$i "
22 ;;
23 $Var_4)
24 echo " $Var_6=$i "
25 ;;
26 $Var_5)
27 echo " $Var_6=$i "
28 ;;
29 $Var_6)
30 echo " $Var_6=$i "
31 esac
32
33 done
得出的结果是
[root@localhost ~]#./mima.sh
ad865d2f63=1000
ad865d2f63=3000
ad865d2f63=6000
ad865d2f63=9000
ad865d2f63=12000
efbaf275cd=15000
函数
函数的命名规则:列举两种常用的
- function name () { 函数体 }
f_name () { 函数体 }
定义本地函数变量
1.function name () { local …}
2.function name () { declare -i … }函数的定义和使用: 可在交互式环境下定义函数 可将函数放在脚本文件中作为它的一部分 可放在只包含函数的单独文件中 调用:函数只有被调用才会执行 调用:给定函数名,函数名出现的地方,会被自动替换为函数代码 函数的生命周期:被调用时创建,返回时终止
事例:交互式定义函数
[root@localhost ~]#seedir () { > ls -l > } [root@localhost ~]#seedir total 39340 -rw-r--r--. 1 root root 0 Sep 3 14:25 11 -rw-r--r-- 1 root root 0 Sep 3 15:17 11.aa -rwxr-xr-x. 1 root root 1075246 Jul 24 10:03 access_log -rwx--x--x. 1 root root 1890 Jul 15 19:51 anaconda-ks.cfg -rwxr-xr-x 1 root root 1247 Sep 3 16:02 auto.sh -rwxr-xr-x. 1 root root 65 Aug 18 11:56 baketc.sh -rwxr-xr-x 1 root root 330 Sep 5 09:19 caidan.sh -rwxr-xr-x. 1 root root 411 Aug 18 13:27 create.sh drwxr-xr-x. 2 root root 6 Jul 15 19:59 Desktop drwxr-xr-x. 2 root root 6 Jul 15 19:59 Documents [root@localhost ~]#
事例:脚本中定义函数
oot@CentOS6 ~]#vim func1 -->编写一个脚本
1 #!/bin/bash
2 #
3 hello() -->定义hello的函数
4 {
5 echo "Hello there today's date is `date +%F`"
6 }
7 echo "now going to the function hello"
8 hello -->调用hello的函数,调用直接输入函数名就可以
9 echo "back from the function"
[root@CentOS6 ~]#chmod +x func1
[root@CentOS6 ~]#./func1 -->执行脚本
now going to the function hello
Hello there today's date is 2017-09-06
back from the function
[root@CentOS6 ~]#
事例:脚本中定义函数的执行值
[root@CentOS6 ~]#vim func1
1 #!/bin/bash
2 #
3 findit()
4 {
5 if [ $# -lt 1 ]; then -->定义之前我们做下判断,脚本有输入的值,如果没有就退出并提示
6 echo "Usage:findit file" 下
7 return 1
8 fi
9 echo "cheng gong" >/root/f1.txt
10 }
11 findit $1 -->这里的$1是下面输入的func1值
[root@CentOS6 ~]#./func1 func1 -->脚本后的func1是$1的值
[root@CentOS6 ~]#cat /root/f1.txt
cheng gong
[root@CentOS6 ~]#
卸载函数:
unset findit 跟平时取消变量一样,unset 加上函数名称就行
最后说个fork炸弹 :(){ :|:& };: 仅供参考,请勿使用,如有使用,提前做好系统备份