Loading

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)......




posted @ 2020-02-15 21:07  云起时。  阅读(366)  评论(0编辑  收藏  举报