41、shell编程基础
bash的变量默认都是全局变量,脚本内都可以调用,无论在什么位置(函数体中也一样),即函数体外可以调用函数体内的变量;
local一般用于局部变量声明,多在函数体内使用;
如果要变为局部变量,则要使用local;
程序是从上而下运行的;
如果全局变量和局部变量名相同,则优先使用局部变量(强龙不压地头蛇);
1、什么是shell:
shell是一个命令解释器,它在操作系统的最外层,负责直接与用户对话,把用户的输入解释给操作系统,并处理
各种各样的操作系统输出结果,输出到屏幕返回给用户,这种对话方式可以是交互式或者非交互式的方式;
2、shell编程步骤:
将linux命令放到文件中去执行,就是shell脚本;
第一:必须root才能执行脚本,否则退出;#用于非root用户上传脚本文件误操作系统,安装的软件执行文件在root用户下执行;
第二:成功切换目录,否则退出;
第三:清理日志,清理成功,再输出;
第四:echo输出;
3、shell脚本在工作中的的作用地位:
shell脚本很擅长处理纯文本类型的数据,而linux系统中几乎所有的配置文件、日志文件、多数启动文件都是纯文本类型的
文件。
4、查看系统支持的shell类型:
[root@backup ~]# cat /etc/shells
/bin/sh
/bin/bash #bash的功能比sh的功能更强大;
/sbin/nologin
/bin/dash
/bin/tcsh
/bin/csh
通常的情况下/bin/sh和/bin/bash是通用的;
5、操作符:
(1)文件操作符:
1)参数解释:
&&:表示成立;
||:表示不成立;
在[ ]中使用:
-f:文件存在且为普通文件则真;
-d:文件存在且为目录文件则真;
-s:文件存在且文件大小不为0为则真;
-e:文件存在为真,不管是目录文件还是普通文件;
-r:文件存在且可读为真;
-w:文件存在且可写为真;
-x:文件存在且可执行为真;
-L:文件存在且为软链接文件文件为真;
file1 -nt file2:文件file1比file2新则真,包括目录文件;
file1 -ot file2:文件file1比file2旧则真;
linux系统一切皆文件;上述文件包括目录文件和普通文件,以后类推;
2)应用实例:
[root@backup ~]# file1=a
[root@backup ~]# [ -e $file1 ]&&echo 1 || echo 0 #不区分文件类型;
1
[root@backup ~]# [ -f $file1 ]&&echo 1 || echo 0 #文件存在打印‘1’,文件不存在打印‘0’
1
[root@backup ~]# [ -x $file1 ]&&echo 1 || echo 0 #执行
0
[root@backup ~]# [ -w $file1 ]&&echo 1 || echo 0 #写
1
[root@backup ~]# [ -d $file1 ]&&echo 1 || echo 0 #目录
0
[root@backup ~]# [ -r $file1 ]&&echo 1 || echo 0 #读
1
(2)字符串操作符:
1)参数解释:
在[ ]中使用:
-z "字符串": 若字符长度为0则真,-z可以理解为zero;
-n "字符串":若字符串长度不为0则真,-n可以理解为no zero;
"字符串1" != "字符串2":若字符串1不等于字符串2则真,但不能使用!==的格式;
特别注意的是,以上的字符串测试必须用""引起来,比较符的两端要有空格;
2)应用实例:
[root@backup ~]# [ -z "123" ]&&echo 1||echo 0
0
[root@backup ~]# [ -n "123" ]&&echo 1||echo 0
1
[root@backup ~]# [ "123" != "123" ]&&echo 1||echo 0
0
[root@backup ~]# [ "123" = "123" ]&&echo 1||echo 0
1
(3)整数比较操作符:
1)参数介绍:
$1:表示输入的内容;
{}:表示一个整体;
在[ ]中的写法 在 (( ))中的写法
-eq:表示等于; ==或=
-ne:表示不等于,not equal; !=
-gt:表示大于,greater than; >
-ge:表示大于等于 greater equal; >=
-lt:小于,less than; <
-le:小于等于 less equal; <=
2)应用实例:
[root@backup ~]# cat test1.sh
[ $1 -eq 3 ]&&{
echo 1
echo 1
echo 1
}
[root@backup ~]# chmod u+x test1.sh
[root@backup ~]# sh test1.sh 3
1
1
1
[root@backup ~]# [ 1 -eq 2 ]&&echo 1||echo 0
0
[root@backup ~]# [ 1 -ne 2 ]&&echo 1||echo 0
1
[root@backup ~]# [ 1 -le 2 ]&&echo 1||echo 0
1
[root@backup ~]# [ 1 -lt 2 ]&&echo 1||echo 0
1
[root@backup ~]# [ 1 -gt 2 ]&&echo 1||echo 0
0
[root@backup ~]# [ 1 -ge 2 ]&&echo 1||echo 0
0
[root@backup ~]# ((5 > 32))&&echo 1||echo 0
0
(4)逻辑连接符:
1)参数说明:
在[ ]中的写法: 在[[ ]] (( ))中的写法:
-a(and,做乘法) && #逻辑与,两边条件都为真则真,一边假为假;
-o (or,做加法) || #逻辑或,两边条件有一真则真;
! ! #非,相反则为真;
2)应用实例:
[root@backup ~]# f1=/etc/rc.local f2=/etc/services
[root@backup ~]# echo $f1
/etc/rc.local
[root@backup ~]# echo $f2
/etc/services
[root@backup ~]# [ -f $f1 -a $f2 ]&&echo 1||echo 0
1
[root@backup ~]# a=1
[root@backup ~]# b=2
[root@backup ~]# [ $a -eq 2 -a $b -eq 2 ]&&echo 1||echo 0
0
[root@backup ~]# [ $a -eq 1 -a $b -eq 2 ]&&echo 1||echo 0
1
6、分支与循环结构:
(1)单分支结构:
if [ 条件 ]
then
指令
fi
或
if [ 条件 ];then
指令
fi
相当于:[ -f /etc/rc.local ]&&{
指令
}
(2)多分支结构:
if [ 条件 ]
then
指令1
else
指令2
fi
或
if [ 条件 ];then
指令1
else
指令2
fi
或
if [ 条件 ];then
指令1
elif [ 条件 ];then
指令2
else
指令3
fi
相当于:[ -f /etc/rc.local ]&&{
指令
}||{
指令
}
7、shell的特殊位置变量:
(1)参数解释:
$0 #脚本本身的名字;
$1,$2 #$1:传递给该shell脚本的第一个参数;$2:传递给该shell脚本的第二个参数;
$* # 获取所有传参的参数,他会把将所有的参数视为单个字符串;
$# #传递给脚本的参数个数;
$$ #脚本当前运行的进程号id;
$? #显示最后命令的退出状态,0表示没有错误,其它表示错误;
$@ #它把程序里的所有参数,以"$1""$2""$3"来显示,每一个都是独立的个体;
1)应用实例:
[root@backup scripts]# vim test2.sh
#!/bin/sh
echo "参数1:$1"
echo "参数2:$2"
echo "参数3:$3"
echo "参数列表:$@"
echo "参数个数:$#"
echo "脚本运行的pid:$$"
echo "脚本完成后是否有错误:$?"
echo "参数变量:$*"
echo "脚本名称:$0"
[root@backup scripts]# sh test2.sh 1 2 3
参数1:1
参数2:2
参数3:3
参数列表:1 2 3
参数个数:3
脚本运行的pid:2305
脚本完成后是否有错误:0
参数变量:1 2 3
脚本名称:test2.sh
(2)./和source于bash或sh执行脚本的区别:
1)source:
source FileName
作用:在当前bash环境下读取并执行FileName中的命令,该FileName文件可以无执行权限;
该命令可以用 "."代替;
例如:. /etc/profile 和source /etc/profile等效;
该命令通常用于重新执行刚修改的初始化文档;
source命令是bash shell的内置命令;
2)sh,bash:
sh/base FileName
作用:打开一个shell来读取FileName中的命令,该FileName文件可以没有执行的权限;
运行一个shell脚本时会启动另一个命令解释器;
每一个shell脚本有效的运行在父shell的一个子进程中;
3)./:
./FileName(当前脚本所在的目录) = /path/FileName
作用:打开一个shell来读取FileName中的命令,该FileName需要执行的权限;
运行一个shell脚本时会启动另一个命令解释器;
每个shell脚本有有效的运行父shell的一个子进程中;
4)注意点:
shell脚本是从上往下进行执行的,要注意条件顺序的使用,函数之间的调用可以不用按顺序排列;
export PATH=/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/sbin
根据脚本所使用的命令来判断脚本适合的用户;
(3)取变量或字符串长度方法(不低于三种):
[root@backup scripts]# A="1,2"
[root@backup scripts]# echo "${#A}"
3
[root@backup scripts]# echo $A|wc -L
3
[root@backup scripts]# expr length "${A}"
3
(4)如何进行整数的计算:
expr(())、bc、$[]、awk、typeset、$(())
expr的效率最高;
1)bc:
可以使用小数
[root@backup scripts]# i=2
[root@backup scripts]# i=`echo $i+1|bc` #效率低;
[root@backup scripts]# echo $i
3
[root@backup scripts]# echo 3.5+2|bc
5.5
[root@backup scripts]# echo 8*7.6|bc
60.8
2) $(()):
[root@backup scripts]# echo $((1+1))
2
[root@backup scripts]# echo $((21*100))
2100
3)$[]:
[root@backup scripts]# echo $[4/5]
0
[root@backup scripts]# echo $[4*5]
20
4)awk:
可以使用小数;
[root@backup scripts]# echo "5.5 5.6"|awk '{print ($2-$1)}'
0.1
[root@backup scripts]# echo "5.5 5.6"|awk '{print ($2*$1)}'
30.8
5)typeset:
[root@backup scripts]# typeset -i num1=1 num2=2
[root@backup scripts]# num1=num1+num2
[root@backup scripts]# echo $num1
3
6)expr:
[root@backup scripts]# expr 10 + 7
17
[root@backup scripts]# expr 10 - 7
3
[root@backup scripts]# expr 10 \* 7
70
[root@backup scripts]# expr 10 / 7
1
(5)单引号、双引号、不加引号,反引号的区别:
单引号:所见即所得 不解析变量;
双引号:解析变量;
不加引号:简单的,连续的,整体的,路径,字符串,有命令要用反引号,可用双引号替代;
反引号:一般用于引用命令,执行的时候命令会被执行,相当于$();
6)把命令行替换为变量方法:
把命令行用$()括起来;
把命令行用反引号``括起来;
扩展:替换变量的方法:
${}=$var,不同点是使用${}会比较精确的界定变量名称的范围;
8、shell变量的输入:
shell 变量除了可以直接赋值或脚本传参外,还可以使用read命令从标准输入获得,read为bash内置命令;
相当于变量的赋值;
语法格式:read [参数] [变量名]
参数解释:
-p:设置提示信息;
-t:设置输入等待的时间,单位默认是秒;
(1)应用实例:
[root@backup scripts]# echo 123q|sed -r 's#[^0-9]##g'
123
[root@backup scripts]# read -p "please input one num:" num
please input one num:123
[root@backup scripts]# echo $num
123
[root@backup scripts]# read -t 5 -p "please input one num:" num
please input one num:[root@backup scripts]#
9、条件测试与比较:
在base的各种流程控制结构中通常要进行各种测试,然后根据测试结果执行不同的操作,有时也会通过与
if等条件语句相结合,更方便的完成判断;
(1)条件测试的语法形式:
格式一:test <测试表达式>
格式二:[ <测试表达式> ]
格式三:[[ <测试表达式> ]] #和表达式一和二的区别是使用逻辑表达式为&&、||、!;
格式一和格式二的写法是等价的,格式三是格式一和格式二的扩展,常用第二种格式;
(2)应用实例:
[root@backup scripts]# test -x c1.sh&&echo 1||echo 0
1
[root@backup scripts]# [ -x c1.sh ]&&echo 1||echo 0
1
[root@backup scripts]# [[ -f c1.sh ]]&&echo 1||echo 0
1
[root@backup scripts]# [ -f c1.sh -o -x c2.sh ]&&echo 1||echo 0
1
[root@backup scripts]# [[ -f c1.sh && -x c2.sh ]]&&echo 1||echo 0
1
10、函数:
(1)函数介绍:
函数的作用就是把程序里多次调用相同的代码部分定义成一份,然后为这一份代码起个名字,其它
所有的重复调用这部分代码就都只条用这个名字就可以了,当需要修改这部分重复代码时,只需要改变
函数体内的一部分代码即可实现所有调用修改;
好处:
思路清晰,增加代码的易读性;
重复调用,减少代码量;
实现程序功能的模块化;
(2)语法格式:
1)简单语法格式:
函数名(){
指令
return n
}
2)规范语法格式:
function 函数名(){
指令
return n
}
(3)提示:
linux中的2000个命令都可以理解为shell的函数;
函数的传参和脚本的传参类似,只是脚本名换成了函数名;
(4)应用实例:
1)定义函数:
[root@backup scripts]# vim c10.sh
#!/bin/sh
function lc(){
echo "I am is liuchang"
}
lc
[root@backup scripts]# sh c10.sh
I am is liuchang
2)调用其它脚本中的函数;
[root@backup scripts]# vim c10.sh
#!/bin/sh
function lc(){
echo "I am is liuchang"
}
[root@backup scripts]# vim c11.sh
#!/bin/sh
. /server/scripts/c10.sh
lc
[root@backup scripts]# sh c11.sh
I am is liuchang
3)函数的传参:
[root@backup scripts]# vim c10.sh
#!/bin/sh
function lc(){
echo "I am is $1"
}
[root@backup scripts]# vim c11.sh
#!/bin/sh
. /server/scripts/c10.sh
lc $1
[root@backup scripts]# sh c11.sh liu
I am is liu
11、shell脚本颜色显示:
[root@backup scripts]# vim c14.sh
#!/bin/bash
#
#下面是字体输出颜色及终端格式控制
#字体色范围:30-37
echo -e "\033[30m 黑色字 \033[0m"
echo -e "\033[31m 红色字 \033[0m"
echo -e "\033[32m 绿色字 \033[0m"
echo -e "\033[33m 黄色字 \033[0m"
echo -e "\033[34m 蓝色字 \033[0m"
echo -e "\033[35m 紫色字 \033[0m"
echo -e "\033[36m 天蓝字 \033[0m"
echo -e "\033[37m 白色字 \033[0m"
#字背景颜色范围:40-47
echo -e "\033[40;37m 黑底白字 \033[0m"
echo -e "\033[41;30m 红底黑字 \033[0m"
echo -e "\033[42;34m 绿底蓝字 \033[0m"
echo -e "\033[43;34m 黄底蓝字 \033[0m"
echo -e "\033[44;30m 蓝底黑字 \033[0m"
echo -e "\033[45;30m 紫底黑字 \033[0m"
echo -e "\033[46;30m 天蓝底黑字 \033[0m"
echo -e "\033[47;34m 白底蓝字 \033[0m"
#控制选项说明
#\033[0m 关闭所有属性
#\033[1m 设置高亮度
#\033[4m 下划线
echo -e "\033[4;31m 下划线红字 \033[0m"
#闪烁
echo -e "\033[5;34m 红字在闪烁 \033[0m"
#反影
echo -e "\033[8m 消隐 \033[0m "
#\033[30m-\033[37m 设置前景色
#\033[40m-\033[47m 设置背景色
#\033[nA光标上移n行
#\033[nB光标下移n行
echo -e "\033[4A 光标上移4行 \033[0m"
#\033[nC光标右移n行
#\033[nD光标左移n行
#\033[y;xH设置光标位置
#\033[2J清屏
#\033[K清除从光标到行尾的内容
echo -e "\033[K 清除光标到行尾的内容 \033[0m"
#\033[s 保存光标位置
#\033[u 恢复光标位置
#\033[?25| 隐藏光标
#\033[?25h 显示光标
echo -e "\033[?25l 隐藏光标 \033[0m"
echo -e "\033[?25h 显示光标 \033[0m"
RED_COLOR="\E[1;31m" #1代表颜色加深; E代表033
RES="\E[0m"
12、case语句:
1)case语句时if的多分支结构;
2)case的语法结构:
case "字符串变量" in
值1)
指令1
;;
值2)
指令2
;;
* )
指令3
;;
esac
13、while条件句:
while循环工作中使用的不多,一般是守护进程程序会用,或始终循环执行;
其它循环计算,都会使用for替换while;
(1)while条件句(先判断后执行):
while 条件; do
指令
done
1)代码:
[root@backup scripts]# vim c17.sh
#!/bin/sh
sum=0
i=1
while [ $i -le 100 ]; do #while(($i <= 100))
((sum=sum+i))
((i++))
done
echo "$sum"
(2)untile条件句(先执行后判断):
until 条件
do
指令
done
提示:untile使用的场合不多,了解就好;
(3)休息命令:
sleep 1 #休息1秒,usleep 1000000 #休息1秒,usleep是微秒
提示:如果休息时间大于大于1分钟就使用定时任务;
(4)脚本进程命令:
1)[root@backup scripts]# vim c17.sh
#!/bin/sh
while true; do
uptime >>./time.log
usleep 1000000
done
2)脚本后台执行:
3)防止脚本运行中断;
[root@backup lc]#nohup -e `sed -i "s#1#3#g" /data/3306/data/lc/a` >/dev/null 2>/tmp/ccc &
#用法和&一样,缺点是当前的终端不能够退出;
[root@backup scripts]# sh c17.sh &
[1] 3611
[root@backup scripts]# ps -ef | grep 3611
root 3611 3369 0 16:35 pts/0 00:00:00 sh c17.sh
root 3663 3611 0 16:36 pts/0 00:00:00 usleep 1000000
root 3665 3369 0 16:36 pts/0 00:00:00 grep 3611
[root@backup scripts]# ps -ef | grep c17.sh
root 3611 3369 0 16:35 pts/0 00:00:01 sh c17.sh
root 6318 3369 0 16:57 pts/0 00:00:00 grep c17.sh
[root@backup scripts]# kill -9 3611
4)以下命令会在用户退出后无法使用,但是进程还在运行:
[root@backup scripts]# sh c17.sh
^Z #ctrl+z:脚本后暂停
[1]+ Stopped sh c17.sh
[root@backup scripts]# bg 1 #脚本后台执行
[1]+ sh c17.sh &
[root@backup scripts]# jobs #查看后台运行的脚本
[1]+ Running sh c17.sh &
[root@backup scripts]# fg 1 #把后台运行的脚本放到前台
sh c17.sh
^Z #ctrl+z:脚本暂停
[1]+ Stopped sh c17.sh
[root@backup scripts]# bg 1 #脚本后台执行
[1]+ sh c17.sh &
[root@backup scripts]# kill %1 #杀死脚本进程
[root@backup scripts]# ps -ef |grep -v|grep %1
root 8342 3369 0 17:23 pts/0 00:00:00 grep %1
[1]+ 已终止 sh c17.sh
5)如何查看系统占用cpu高:
top
[root@backup scripts]# strace -p 1
Process 1 attached
select(8, [3 5 6 7], [], [7], NULL
6) pstree:
查看运行的服务:
[root@m01 ~]# pstree
init─┬─crond
├─6*[mingetty]
├─nginx───nginx
├─portreserve
├─rpc.statd
├─rpcbind
├─rsyslogd───3*[{rsyslogd}]
├─salt-master─┬─3*[salt-master───2*[{salt-master}]]
│ └─salt-master─┬─5*[salt-master───18*[{salt-master}]]
│ └─salt-master───6*[{salt-master}]
├─sshd───sshd───sshd───bash───su───bash───pstree
└─udevd───udevd
有服务进程名的不一定有端口号,但是有端口号的一定有服务进程名;
有服务进程名的一定有进程pid;
有端口号的服务监听端口号,netstat -tunlp;没有端口号的服务监听服务进程ps -ef
14、for循环:
(1)语法:
1)for 变量名 in 变量取值列表; do
指令
done
2)for ((exp1;exp2;exp3)); do
指令
done
(2)代码:
1)[root@backup scripts]# vim c21.sh
#!/bin/sh
for n in {1..10}; do
echo $n
done
2)[root@backup scripts]# vim c21.sh
#!/bin/sh
for ((i=1;i<=10;i++)); do
echo $i
done
15、break、continue、exit、return的用法:
break n #n表示跳出循环的层数,如果省略n表示跳出整个循环;
continue n #n表示退到第n层继续循环,如果省略n表示跳出本次循环,
忽略本次循环的剩余代码,进入循环的下一次循环;
exit n #退出当前的shell程序,n为返回值,n也可以省略,在shell里通过$?接收这个n的值;
return n #用于在函数里,作为函数的返回值,用于判断函数执行是否正确;
[root@backup scripts]# vim c24.sh
#!/bin/sh
for ((i=1;i<=5;i++)); do
if [ $i -eq 3 ]; then
# break #1、2、end
# exit #1、2
continue #1、2、4、5、end
fi
echo $i
done
echo "end"
16、shell数组:
(1)数组介绍:
平时的定义a=1;b=2;c=3。变量如果多了,再一个一个定义很费劲,并且取变量的也费劲;
简单的说,数组就是各种数据类型的元素按一定顺序排列的集合;
数组就是把有限个元素变量或数据用一个名字名字,然后用编号区分他们的变量的集合。这个
名字成为数组名,编号成为数组下标。组成数组的各个变量成为数组的分量,也成为数组的元素,有
时也称为下标变量;
(2)数组取值:
数组的下标是从0开始的;数组是一个变量,${} 中带#是长度,不带是求字符,数组和字符串只是[*]\[1]的区别;
#定义数组
[root@backup scripts]# array=(1 2 3) #静态数组
#打印数组的长度
[root@backup scripts]# echo ${#array[*]}
3
#依次打印数组的下标:
[root@backup scripts]# echo ${!array[*]}
0 1 2
#取数组的下标取数组的值;
[root@backup scripts]# echo ${array[0]}
1
[root@backup scripts]# echo ${array[1]}
2
[root@backup scripts]# echo ${array[2]}
3
#取出数组所有的值:
[root@backup scripts]# echo ${array[*]}
1 2 3
#数组的追加:
[root@backup scripts]# array[3]=4
[root@backup scripts]# echo ${array[*]}
1 2 3 4
#数组元素的删除:
[root@backup scripts]# unset array[3]
[root@backup scripts]# echo ${array[*]}
1 2
#删除整个数组:
[root@backup scripts]# unset array
[root@backup scripts]# echo ${array[*]}
[root@backup scripts]#
#数组的截取:
[root@backup scripts]# array=(1 2 3 4 5 6)
[root@backup scripts]# echo ${array[*]}
1 2 3 4 5 6
[root@backup scripts]# echo ${array[*]:1:3}
2 3 4
(3)数组中存放命令(动态数组):
在数组中将命令用$或反引号(``)括起来就可以了;
[root@backup scripts]# array=(`echo $(date)` $(ls /server/scripts/))
[root@backup scripts]# echo ${array[*]}
2019年 01月 14日 星期一 12:24:51 CST access_log a.txt c10.sh c11.sh c12.sh c13.sh c14.sh c15.sh c17.sh c18.sh c19.sh c1.sh c20.sh c21.sh c22.sh c23.sh c24.sh c25.sh c2.sh c3.sh c4.sh c5.sh c6.sh c7.sh c8.sh c9.sh check_del_data.sh lamp.sh lc_123.sh lnmp.sh nohup.out test test1.sh test2.sh test.sh time.log
[root@backup scripts]# echo ${array[0]}
2019年
[root@backup scripts]# echo ${array[1]}
01月
[root@backup scripts]# echo ${array[6]}
access_log
[root@backup scripts]# echo ${array[7]}
a.txt
(4)代码示例:
[root@backup scripts]# vim c25.sh
#!/bin/sh
array=(10.0.0.1
10.0.0.2
10.0.0.3)
for ((i=0;i<${#array[*]};i++)); do
echo ${array[$i]}
done
[root@backup scripts]# vim c25.sh #数组常用此法循环,更方便;
#!/bin/sh
array=(10.0.0.1
10.0.0.2
10.0.0.3)
for ip in ${array[*]}; do
sleep 3
echo $ip
done
(5)数组总结:
17、shell脚本的调试:
(1)学习脚本的开发规范;
(2)[root@backup scripts]# sh c27.sh
c27.sh: line 5: syntax error: unexpected end of file
c27.sh:第5行:语法错误:意外的文件结尾
中括号两边没有空格会报命令找不到的错误;
(3)脚本要清晰,简介;
(4)
(5)在windows下面开发的shell脚本:
在windows下开发的脚本放到linux中会出现"^M"符号,这会导致脚本在运行的时候报
脚本语法错误,一般情况下是看不出脚本有任何问题的,所以需要使用dos2unix命令对shell脚本
进行处理,默认情况下dosunix是没有安装,需要进行yum安装;
(6)在调试逻辑错误的时候:
逐步使用echo和exit进行断点调试,非常有效;
(7)使用sh base进行调试:
1)-n:不会执行该脚本,仅查询脚本语法是否有问题,并给出错误提示;
2)-v:在执行脚本的时候,先将脚本的内容输出到屏幕上,然后执行脚本,如果有错误会给出错误提示;
3)-x:将执行的脚本内容及输出显示到屏幕上,如果有错误会给出错误提示,这个对调试脚本很有用,最常用;
A、普通调试:
[root@backup scripts]# vim c25.sh
#!/bin/sh
array=(10.0.0.1
10.0.0.2
10.0.0.3)
for ip in ${array[*]}; do
sleep 3
echo $ip
done
[root@backup scripts]# sh -x c25.sh
+ array=(10.0.0.1 10.0.0.2 10.0.0.3)
+ for ip in '${array[*]}'
+ sleep 3
+ echo 10.0.0.1
10.0.0.1
+ for ip in '${array[*]}'
+ sleep 3
+ echo 10.0.0.2
10.0.0.2
+ for ip in '${array[*]}'
+ sleep 3
+ echo 10.0.0.3
10.0.0.3
B、针对特定的代码行进行调试,缩小调试的作用域:
a、shell脚本的调试:
[root@backup scripts]# vim c25.sh
#!/bin/sh
array=(10.0.0.1
10.0.0.2
10.0.0.3)
for ip in ${array[*]}; do
sleep 3
set -x #输出开始
echo $ip
set +x #输出结束
done
[root@backup scripts]# sh -x c25.sh
+ array=(10.0.0.1 10.0.0.2 10.0.0.3)
+ for ip in '${array[*]}'
+ sleep 3
+ set -x
+ echo 10.0.0.1
10.0.0.1
+ set +x
+ echo 10.0.0.2
10.0.0.2
+ set +x
+ echo 10.0.0.3
10.0.0.3
+ set +x
b、命令行的调试:
[root@backup scripts]# set -x #增加调试
[root@backup scripts]# for ((i=1;i<3;i++)); do echo $i;done
+ (( i=1 ))
+ (( i<3 ))
+ echo 1
1
+ (( i++ ))
+ (( i<3 ))
+ echo 2
2
+ (( i++ ))
+ (( i<3 ))
[root@backup scripts]# set +x #结束调试
+ set +x
[root@backup scripts]# for ((i=1;i<3;i++)); do echo $i;done
1
2
(8)shell脚本调试技巧总结:
1)要记得首先使用dos2unxi对脚本格式化;
2)直接执行脚本根据报错来调试,但是有时的报错不准确;
3)sh -x调试整个脚本,显示执行的过程(大海捞针困难),适用于小的脚本;
4)set -x和set +x调试部分脚本(脚本中设置)(南印度洋所有调试范围),适用于大型脚本;
5)echo输出变量及相关内容,然后紧跟exit退出,不执行后面程序的方法跟踪脚本,对于
逻辑错误比较好用,写法是echo $var;exit;
6)最关键的是语法熟练、编码习惯、编程思想、将错误扼杀在萌芽之中,减轻调试负担,提高
效率;
18、shell开发环境的配置调整和优化:
(1)下载地址:
官方下载地址:https://github.com/ma6174/vim-deprecated
安装命令:wget -qO- https://raw.github.com/ma6174/vim/master/setup.sh | sh -x
直接放入用户的家目录中;
(2)具体的功能:
1)按F5可以直接编译并执行C、C++、java代码以及执行shell脚本,按“F8”可进行C、C++代码的调试
2)自动插入文件头 ,新建C、C++源文件时自动插入表头:包括文件名、作者、联系方式、建立时间等,读者可根据需求自行更改
3)映射“Ctrl + A”为全选并复制快捷键,方便复制代码
4)按“F2”可以直接消除代码中的空行
5)“F3”可列出当前目录文件,打开树状文件目录
6)支持鼠标选择、方向键移动
7) 代码高亮,自动缩进,显示行号,显示状态行
8)按“Ctrl + P”可自动补全
9)[]、{}、()、""、' '等都自动补全
10)......