shell基础(六)脚本规范及Linux信号知识

一、shell脚本规范事项

1.脚本第一行加脚本解释器:#!/bin/bash 或 #!/bin/sh
2.若脚本中有中文,则需要在系统中加”export LANG=”zh_CN.UTF-8″”,并且在脚本中重新定义字符集,使其和系统中的字符集一致
3.shell脚本以.sh结尾,并且放到制定位置:例如”/server/scripts”
4.所以成对的符号,和循环语句的关键词,要一次性写完,防止遗漏
5.全局变量全部大写,局部变量可以全部小写或者使用驼峰语法进行书写,例如:”myBook”
6.函数命名可采用首字母大写,并且语义要清晰,例如:”createFile”
7.尽量在函数最后加上返回值,有些不会用到返回值的也一样

二、高级命名规范:

1.常规shell用.sh结尾:例如:shell.sh
2.模块的启动和停止脚本统一命名为start_模块名.sh和stop_模块名.sh
3.监控脚本一般以_mon.sh结尾
4.控制脚本一般以
_ctl.sh为后缀

三、shell脚本的变量和文件检查规范

在脚本中要检查配置项是否为空、是否可执行等,尤其是对于一些重要的、会影响下面脚本正常运行的配置项,需要进行是否为空的检查。

字符子串的特殊用法:
${变量:-word}:若变量值为空或未赋值,则返回word字符串并代替变量的值
    用于:如果变量未定义,则返回备用值,防止因为变量未定义或为空而导致异常
${变量:=word}:若变量值为空或未赋值,则设置这个变量的值为word,并且返回其值,位置变量和特殊变量不适用
    用于:基本上同第一个,只是在第一个的基础上又额外给了“变量赋值”
${变量:?word}:若变量值为空或未赋值,则word字符串将被作为标准错误输出,否则输出变量的值
    用于:捕捉由于变量未定义而导致的错误,并退出程序
${变量:+word}:若变量值为空或未赋值,则什么也不做,否则word字符串将代替变量的值

注:
  若将":"去掉,则将定义中的"若变量值为空或未赋值"改为"未赋值",用于测试变量是否赋值
例一:
[centos@mycentos ~]$ echo $test #变量为空
[centos@mycentos ~]$ res=${test:-UNSET}
[centos@mycentos ~]$ echo $res        #打印res变量,返回UNSET,因为test没有赋值 
UNSET
[centos@mycentos ~]$ echo $test  #test仍然没有值

对于${test:-UNSET},当test变量没有值时,就返回变量结尾设置的UNSET字符串,有值时就返回test的值。

例子二:
[centos@mycentos ~]$ unset test  #test为空
[centos@mycentos ~]$ unset res   #res为空
[centos@mycentos ~]$ echo $res

[centos@mycentos ~]$ res=${test:=UNSET}  #对res变量进行赋值
[centos@mycentos ~]$ echo $res      #因为test为空,所以打印UNSET
UNSET
[centos@mycentos ~]$ echo $test     #此处test被赋值,原来是没有定义的,与例一有所不同
UNSET
结论:
${变量:=word}
当变量(res)和变量(test)值没有定义时,会给变量(res)赋值":="后面的内容,同时会把":="后面的内容赋值给变量test,此方法可以解决变量没有定义的问题,确保没有定义的变量始终有值

例子三:
[centos@mycentos ~]$ echo ${key:?not defined}
-bash: key: not defined
[centos@mycentos ~]$ key=1
[centos@mycentos ~]$ echo ${key:?not defined}
1
[centos@mycentos ~]$ unset key
[centos@mycentos ~]$ echo ${key:?not defined}
-bash: key: not defined

${变量:?word}此例可以用于设置变量未定义二报错的具体内容,如"not defined"


例子四:
[centos@mycentos ~]$ oldboy=${oldgirl:+word}
[centos@mycentos ~]$ echo $oldboy  #oldgril没有赋值,所以打印变量oldboy为空

[centos@mycentos ~]$ oldgirl=19 
[centos@mycentos ~]$ oldboy=${oldgirl:+word} #此处需要重新定义
[centos@mycentos ~]$ echo $oldboy               #oldgirl有值后,打印出来":+"后面的内容
word
此例可用于测试变量(oldboy位置)是否存在,若oldboy的值为word,则证明oldgirl变量有值存在

在系统脚本中看防止变量为空的应用:

在apache1服务启动脚本/etc/init.d/httpd中
  1 #!/bin/bash
  2 #
  3 # httpd        Startup script for the Apache HTTP Server
  4 #
  5 # chkconfig: - 85 15
  6 # description: The Apache HTTP Server is an efficient and extensible  \
  7 #              server implementing the current HTTP standards.
  8 # processname: httpd
  9 # config: /etc/httpd/conf/httpd.conf
 10 # config: /etc/sysconfig/httpd
 11 # pidfile: /var/run/httpd/httpd.pid
 12 #
 13 ### BEGIN INIT INFO
 14 # Provides: httpd
 15 # Required-Start: $local_fs $remote_fs $network $named
 16 # Required-Stop: $local_fs $remote_fs $network
 17 # Should-Start: distcache
 18 # Short-Description: start and stop Apache HTTP Server
 19 # Description: The Apache HTTP Server is an extensible server 
 20 #  implementing the current HTTP standards.
 21 ### END INIT INFO
 22 
 23 # Source function library.
 24 . /etc/rc.d/init.d/functions
 25 
 26 if [ -f /etc/sysconfig/httpd ]; then
 27         . /etc/sysconfig/httpd
 28 fi
 29 
 30 # Start httpd in the C locale by default.
 31 HTTPD_LANG=${HTTPD_LANG-"C"}  #若HTTPD_LANG变量没有赋值(没有定义),则将HTTPD_LANG值变,此处为":"省略的情况
    
 33 # This will prevent initlog from swallowing up a pass-phrase prompt if
 34 # mod_ssl needs a pass-phrase from the user.
 35 INITLOG_ARGS=""
 36 
 37 # Set HTTPD=/usr/sbin/httpd.worker in /etc/sysconfig/httpd to use a server
 38 # with the thread-based "worker" MPM; BE WARNED that some modules may not
 39 # work correctly with a thread-based MPM; notably PHP will refuse to start.
 40 
 41 # Path to the apachectl script, server binary, and short-form for messages.
 42 apachectl=/usr/sbin/apachectl
 43 httpd=${HTTPD-/usr/sbin/httpd} #若HTTPD没有赋值(没有定义):则将httpd赋值为"/usr/sbin/httpd"
 44 prog=httpd

注:
  1.在企业中,针对目录路径情况等的处理就可以采用上述变量不存在的方式,防止因目录不存在而导致的异常

实战一:删除7天前的过期数据备份

[centos@mycentos shell]$ cat 1.sh 
#!/bin/bash
sudo find ${path-/tmp} -name "*.tar.gz" -type f -mtime +7 |xargs rm -f

1.如果忘记了定义path路径变量,又不希望其为空,就可以定义/tmp代替path空值返回值.
2.若忘记了定义path路径变量,还没有做特殊变量定义,此条命令会出现异常

补充:http脚本变量的定义方式:

httpd=${HTTPD-/usr/sbin/httpd}
prog=httpd
pidfile=${PIDFILE-/var/run/httpd/httpd.pid}
lockfile=${LOCKFILE-/var/lock/subsys/httpd}

此定义方式可以防止出现空值

四、shell调试技巧

1、使用dos2unix命令处理在Windows下开发的脚本
#!/bin/bash
i=1
sum=0
while((i<=100))
do
    let i++
    ((sum+=i))
done
使用dos2unix进行格式化,会去除一些Windows的一些格式(例如空格)错误
---------------------------------------------------------------------------------------
2.bash命令调试

sh [-nvx] scripts.sh
-n :不会执行脚本,仅仅检查语法是否有问题,并且给出错误提示
-v :在执行脚本时,先将脚本的内容输出到屏幕上,然后执行脚本,如果有错误,也会给出错误提示
-x :将执行的脚本内容输出显示到屏幕上。

printf "totalsum is $sum"
export PS4='+${LINENO}' #此命令可以使追踪命令显示每行的行号

五、vim编辑器的配置

1.编辑vim相关文件

.viminfo     用户使用vim的操作历史记录
.vimrc       当前用户的配置文件
/etc/vimrc   系统全局vim的配置文件
/usr/share/vim/vim74/colors 配色魔板文件存放路径

注:
      1.当配置/etc/vimrc文件时,所有用户的vim均会受影响
      2.当编辑个人用户家目录下的隐藏文件.vimrc,则只有此用户的vim编辑受影响。

以下是个人的vim的配置,直接复制到家用户目录下的.vimrc即可

set nocompatible
set history=100
filetype on
filetype plugin on
filetype indent on
set autoread
set mouse=a
syntax enable
set nofen
set fdl=0
set expandtab
set tabstop=4
set shiftwidth=4
set softtabstop=4
set smarttab
set ai
set si
set wrap
set sw=4
set wildmenu
set nu
set cmdheight=1
set lz
set backspace=eol,start,indent
set whichwrap+=<,>,h,l
set magic
set noerrorbells
set novisualbell
set showmatch
set mat=2
set hlsearch
set ignorecase
set encoding=utf-8
set fileencodings=utf-8
set termencoding=utf-8
set smartindent
set cin
set showmatch
set guioptions-=T
set guioptions-=m
set vb t_vb=
set laststatus=2
set pastetoggle=<F9>
set background=dark
highlight Search ctermbg=black ctermfg=white guifg=white guibg=black

autocmd BufNewFile *.py,*.cc,*.sh,*.java exec ":call SetTitle()"

func SetTitle()
    if expand("%:e") == 'sh'
        call setline(1, "#!/bin/bash")
        call setline(2, "#Auther:itboy")
        call setline(3, "#Time:".strftime("%F %T"))
        call setline(4, "#Name:".expand("%"))
        call setline(5, "#Version:V1.0")
        call setline(6, "#Description:this is a test script.")
    endif
endfunc

2.vim的高级命令

ngg :调到n行
0 :到行开头
$ :到行结尾
L :移动到当前窗口最后一行 == G ,然后点"o",开始下一行编辑
H :移动到当前窗口最前面一行 ==gg 

命令行模式下:"ctrl+:"后
/old  :从上向下找"old"
%s/A/B/g :A全部替换为B "/"可以换成"#或@"
n1,n2 w filename : 将n1到n2行的内容保存到filename文件里
n1,n2 co n3 : 将n1到n2行的内容复制到n3的位置下
n1,n2 m n3 : 将n1到n2行的内容剪切到到n3的位置下
! “命令”  :暂且退出vi,执行“命令”
vs filename  : 竖直分屏显示filename ,q!退出分屏


1.多行注释:
  1). 首先按esc进入命令行模式下,按下Ctrl + v,进入列(也叫区块)模式;
  2). 在行首使用上下键选择需要注释的多行;
  3). 按下键盘(大写)“I”键,进入插入模式;
  4). 然后输入注释符(“//”、“#”等);
  5). 最后按下“Esc”键。 注:在按下esc键后,会稍等一会才会出现注释,不要着急~~时间很短的
 
2.删除多行注释:
  1). 首先按esc进入命令行模式下,按下Ctrl + v, 进入列模式;
  2). 选定要取消注释的多行;
  3). 按下“x”或者“d”. 注意:如果是“//”注释,那需要执行两次该操作,如果是“#”注释,一次即可

3.多行删除
  1).首先在命令模式下,输入“:set nu”显示行号;
  2).通过行号确定你要删除的行; 
  3).命令输入“:32,65d”,回车键,32-65行就被删除了,很快捷吧
      如果无意中删除错了,可以使用‘u’键恢复(命令模式下)
      也可以用"del"在可视化中全删选择的内容

4.多行缩进
  1). 首先按esc进入命令行模式下,按下Ctrl + v,进入列(也叫区块)模式;
  2). 在行首使用上下键选择需要缩进的多行;
  3). 最后按"="即可

六、Linux信号相关知识

一、现象描述:
1.当运行shell脚本时,如果按下Ctrl+c 或Ctrl+x(x为其他字符),程序会终止运行。
2.当不希望shell在运行时被终止,则可以使用屏蔽信号手段,让程序忽略用户输入的信号指令,从而继续运行shell程序。
二、信号含义:
信号是由一个整数构成的异步消息,它可以由某个进程发给其他进程,也可以在用户按下特定按键发生某种异常事件时,由系统发给某个进程。

1.Linux重要信号
HUP(1)  挂起,通常因终端掉线或用户退出而引发
INT(2)  中断,通常因为按ctrl + c组合键而引发
QUIT(3) 退出,通常因为按ctrl + \ 组合键而引发
ABRT(6)  中止 , 通常因为某些严重的执行错误而引发
ALRM(14) 报警 , 通常用来处理超时
TERM(15) 终止 ,通常在系统关机时发送
TSTP(20) 停止进程的运行,但该信号可以被处理和忽略,通常是Ctrl + z键而引发

注:
    shell脚本中可以用数字来代表信号,也可以用信号的名字代表信号
2.trap命令
trap命令:
    1.用于在接受到信号后将要采取的行动
    2.常用于在脚本程序被中断时完成清理工作,或者屏蔽用户非法使用的某些信号
注:
    使用信号名时需要省略前缀"SIG"
用法:
    trap command signal
    signal是接受到的信号 , command是接收到信号后应该采取的行动
    trap "命令;命令" 信号名      或者 trap "命令;命令" 信号编号

例一:

处理单个信号:
[centos@mycentos ~]$ trap "" 2  #若执行动作为空,则可以用来屏蔽与数字对应的Ctrl+c信号
[centos@mycentos ~]$ trap ":" 2 #此处恢复Ctrl + c 的信号 
[centos@mycentos ~]$ ^C    #已恢复

例二:

同时处理多个信号:
[centos@mycentos ~]$ trap "" 1 2 3 20 #<==执行这些数字信号,什么都不做,即屏蔽这些信号
[centos@mycentos ~]$ trap ":" 1 2 3 20 #<==执行这些信号,恢复对应的功能
[centos@mycentos ~]$ ^C
[centos@mycentos ~]$ trap "" HUP INT QUIT TSTP #<==执行这些名称信号,什么都不做,即屏蔽这些信号
[centos@mycentos ~]$ trap ":" HUP INT QUIT TSTP #<==执行这些名称信号,恢复对应的功能
[centos@mycentos ~]$ ^C
[centos@mycentos ~]$ trap "" `echo {1..64}` #<==屏蔽1-64所有的数字信号

实战二:
开发脚本实现触发信号后清理文件功能(信号触发后就会执行将新建的文件删除命令)

#!/bin/bash
#Auther:itboy
#Time:2018-11-20 10:09:42
#Name:3.sh
#Version:V1.0
#Description:this is a test script.

#<==捕获ctrl+c 键后即执行find删除命令,后退出脚本
trap "find /tmp -type f -name "old_*" | xargs rm -f && exit" INT

while true
do
    touch /tmp/old_$(date +%F-%T) #<==在/tmp创建文件
    sleep 5     #<==休息3秒
    ls -la /tmp/old*    #<==查看文件创建情况
done

实战三:
开发脚本,练习QUIT、TSTP、INT

#!/bin/sh
#捕获ctrl+c信号时,执行echo命令
trap 'echo "you are typing ctrl-c ,sorry,script will not terminate"' INT
#捕获Ctrl+\信号,执行echo
trap 'echo "you are typing ctrl-\ ,sorry,script will not terminate"' QUIT
#捕获ctrl+z信号,就会执行echo命令 (实测此处没有执行echo命令)
trap 'echo "you are typing ctrl-z ,sorry,script will not terminate"' TSTP
while true
do
    echo "now , test signal $(date)"
    sleep 5
done

效果如图:

[root@mycentos ~]# sh 2.sh 
now , test signal Tue Nov 20 11:02:06 CST 2018
^Cyou are typing ctrl-c ,sorry,script will not terminate  #按下ctrl+c执行
now , test signal Tue Nov 20 11:02:11 CST 2018
now , test signal Tue Nov 20 11:02:16 CST 2018
now , test signal Tue Nov 20 11:02:21 CST 2018
^\Quit (core dumped)
you are typing ctrl-\ ,sorry,script will not terminate #按下ctrl+\执行
now , test signal Tue Nov 20 11:02:25 CST 2018
now , test signal Tue Nov 20 11:02:30 CST 2018
^Z^Z                            #按下ctrl +z 键没有打印提示,但是程序停止运行了
    原文作者:一名IT小学生
    原文地址: https://www.jianshu.com/p/60322852aabd
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞