1:区分大小写
Linux是区分大小写的,所以,我们写的shell脚本也是区分大小写的
2:特殊字符
3:函数形式:
#1 function name { code } #2 function() { code }
函数部分必须出现在调用它的语句之前,否则必须声明;
4:声明
脚本第一行必须对所调用的编译器进行声明,如:/bin/bash;否则,脚本会在默认的编译器中执行,即用户所在系统定义的shell,在一个非预期的shell中执行可能导致不可预料的错误!
5:注释即风格
#!/bin/bash # # SCRIPT: NAME_of_SCRIPT # AUTHOR: AUTHORS_NAME # DATE: DATE_of_CREATION # REV: 1.1.A (Valid are A, B, D, T, Q, and P) # (For Alpha, Beta, Dev, Test, QA, and Production) # # PLATFORM: (SPECIFY: AIX, HP-UX, Linux, OpenBSD, Solaris, other flavor, # or Not platform dependent) # # REQUIREMENTS: If this script has requirements that need to be noted, this # is the place to spell those requirements in detail. # # EXAMPLE: OpenSSH is required for this shell script to work. # # PURPOSE: Give a clear, and if necessary, long, description of the # purpose of the shell script. This will also help you stay # focused on the task at hand. # # REV LIST: # DATE: DATE_of_REVISION # BY: AUTHOR_of_MODIFICATION # MODIFICATION: Describe what was modified, new features, etc-- # # # set -n # Uncomment to check script syntax, without execution. # # NOTE: Do not forget to put the # comment back in or # # the shell script will never execute! # set -x # Uncomment to debug this shell script # ########################################################## # DEFINE FILES AND VARIABLES HERE ########################################################## THIS_SCRIPT=$(basename $0) ########################################################## # DEFINE FUNCTIONS HERE ########################################################## ########################################################## # BEGINNING OF MAIN ########################################################## # End of script
6:控制语句
if...then语句
if [test_commond] then commands fi
if [test_command] then commands else commands fi
if [test_command] then commands elif [test_command] then commands elis [test_command] then commands : : : else (optional) commands fi
for...in语句
for loop_variable in arguement_list do commands done
while语句
while test_condition_is_true do commands done
until语句
until test_condition_is_true do commands done
case语句
case $variable in match-1) commands_to_execute_for_1 ;; match-2) commands_to_execute_for_2 ;; : : : *)(optional--any other value) commands_to_execute_for_no_match ;; esac
7:break continue return exit用法区别
break:跳出循环
continue :下一轮循环
return:用于在函数中将数据返回,或者是返回一个结果或者是代码给调用脚本
exit:退出整个脚本,将返回码发送给系统
8:here文档
用于将输入重定向到某个交互式脚本或者程序
9:符号命令
他们都允许一次访问所有的命令行参数,除非使用双引号“”将它们括起来,否则它们具有相同的功能!
$*将整个参数列表作为一个参数来获取
$@获取整个参数列表,并将其分隔成不同的参数
[root@pacteralinux shellscript]# ./arguementtest.sh 1 2 3 4 5 1 2 3 4 5 [root@pacteralinux shellscript]# ./arguementtest2.sh 1 2 3 4 5 1 2 3 4 5 [root@pacteralinux shellscript]# cat arguementtest.sh for token in "$*" do echo $token done [root@pacteralinux shellscript]# cat arguementtest2.sh for token in "$@" do echo $token done [root@pacteralinux shellscript]#
11:双引号"",单引号'',短引号``
单引号:所见即所得
双引号:部分——允许字符替换和命令替换
短引号:命令
12:shell脚本中的数学
++ -- + - !~(逻辑非,二进制取反) * / % << >> > < >= <= == != &(按位与) &&(逻辑与) |(按位或) ||(逻辑或) ^(按位异或)
13:内置数学表达式
14:在远程主机上运行命令
ssh user2hostname command_to_execute
15:设置陷阱
脚本结束后会反悔一个退出码,捕捉退出码执行一些操作,就可以在脚本退出之前执行一些操作!不能捕获kill -9信号
[root@pacteralinux shellscript]# cat arguementtest.sh for token in "$*" do echo $token done trap 'echo "\nexit on a trap singal";exit' 1 2 3 15 0
解释:如果脚本以1 2 3 15 0信号退出,将会执行trap
[root@pacteralinux shellscript]# ./arguementtest.sh 22 33 ee gg 22 33 ee gg \nexit on a trap singal
16:与用户通信
17:大小写转换
大写:UPCASE=$(echo $variable|tr '[a-z]' '[A-Z]')
[root@pacteralinux ~]# variable=fuwenchao [root@pacteralinux ~]# UPCASE=$(echo $variable|tr '[a-z]' '[A-Z]') [root@pacteralinux ~]# echo $UPCASE FUWENCHAO [root@pacteralinux ~]#
小写:DOWNCASE=$(echo $variable|tr '[A-Z]' '[a-z]')
可以使用typeset命令控制变量在shell中的属性:
大写:typeset -u VARIABLE
[root@pacteralinux ~]# typeset -u wenchao123 [root@pacteralinux ~]# wenchao123=fuwenchaochaochao [root@pacteralinux ~]# echo $wenchao123 FUWENCHAOCHAOCHAO [root@pacteralinux ~]#
小写:typeset -l
18:检测返回代码$?
命令如果执行成功,返回0,否则,返回除0以外的整数
#测试目录是否存在 [root@pacteralinux shellscript]# ./testdir.sh ./testdir.sh: line 3: [0: command not found dir doesnot exist [root@pacteralinux shellscript]# ./testdir.sh ./testdir.sh: line 3: [0: command not found dir doesnot exist [root@pacteralinux shellscript]# cat testdir.sh #!/bin/bash test -d /usr if ["$?" -eq 0] then echo "dir does exist" else echo "dir doesnot exist" fi #vi testdir.sh [root@pacteralinux shellscript]# ./testdir.sh dir does exist [root@pacteralinux shellscript]# cat testdir.sh #!/bin/bash test -d /usr if [ "$?" -eq 0 ] then echo "dir does exist" else echo "dir doesnot exist" fi [root@pacteralinux shellscript]#
19:输出控制
静默运行:
./scriptname 2>&1>/dev/null #将标准错误重定向到标准输出,然后将所有的输出发送到位桶,这样脚本不会输出任何内容到屏幕
20:使用getopts解析命令行参数
getopts内置与shell中。可以捕获由单个字符所指定的有效命令行参数,单个字符前有一个+或者-号。为指定某个命令行开关项需要一开关参数,可以在开关项后面加一个:号,如果不需要开关项不需要任何参数,:号可以省略。所有这些选项集中到一起称为optionstring,后面跟随一些变量名。没个开关项的参数保存在一个称为OPTARG的变量中。如果整个optionstring前面有一个冒号,则任何未匹配的开关项将导致在variable中加载一个?号,命令的形式如下:
getopts optionstring VARIABLE [arguement......]
对于需要花时间和进程去监控的脚本,可以为他们提供一个参数,即 -s 5 -m 10 -h 1 -p my_backup。注意开关项和参数之间不必存在空格!
注意:对于指定的每个选项s m h d p,在每个开关项后面加入了一个冒号,这就告诉getopts这些开关项需要一个参数。在optionstring之前的冒号要求getopts在给定一个未详细指明的选项时,将TIMED设置为?。这允许使用一个返回码1来调用usage函数和exit函数。
getopts不管接收参数,因此如果希望退出,必须手动执行
最后,while循环最后讲标准错误重定向到位桶,。在遇到一个为详细指明的参数时,getopts将发送一条消息给标准错误!
21:使用后台函数创建一个协作进程
协作进程是前台进程和后台进程之间的通信连接
为什么需要协作进程???
在某个脚本中需要调用一个函数,当我们对主脚本进行定时控制时该函数完成所有的进程监视工作。这时问题就出现了:因为需要在后台运行这个函数,而且这个函数有一无限循环。由于不能通知循环终止,该循环将在主脚本以及函数终止后一直运行,这就导致了一个或者多个死进程,,因此,在主脚本中,需要一种方式来与该循环进行通信,这样后台函数在递减基数结束或者脚本使用ctrl+c键终止后,能够通知终止并且很快退出函数。为了解决这个问题,将proc_watch作为后台协作进程!
理解:协作进程(函数)其实就是一个线程,启动后(方式)完成一些特定的操作,但是如果这个线程中有无限循环的话,主脚本退出后这个线程将会一直运行而消耗系统资源,但是这个线程又是一个死线程,所以又要一种方式与他通信告诉他什么时候结束!!!!!好吧,不多说,理解的最好方式就是看代码
说明:
2个函数:trap_exit(与后台协作进程通信)和proc_watch(后台协作进程)
后台协作进程的启动方式:proc_watch |&
给后台协作进程发送消息print -p $BREAK_OUT,后台进程接收消息read ¥BREAK_OUT
trap陷阱捕获1 2 3 15后调用trap_exit函数并退出exit 2
22:捕获命令的延迟输出
当你希望活的命令输出却灭有捕获到时。until是良药
OUTFILE="/root/file.out" cat /dev/null > $OUTFILE until [ -s $OUTFILE ] #知道file.out不为空 do delayed_output_command >> $OUTFILE done more $FILEOUT
23:逐行处理文件的最快方式
重定向输入方式复制文件
[root@pacteralinux shellscript]# more proctextfast.sh #!/bin/bash OUTFILE=/root/outfile INFILE=/root/infile function while_read_line_bottom_FD_OUT { >$OUTFILE exec 4<&1 #Associate standard output with file descriptor 4 exec 1>$OUTFILE #redirect standard output to $OUTFILE while read LINE do echo $LINE : done<$INFILE exec 1<&4 exec 4>&- #restore standard output and close file descriptor 4 } while_read_line_bottom_FD_OUT [root@pacteralinux shellscript]#
使用文件描述符输入输出文件的方法复制文件
[root@pacteralinux shellscript]# more proctextfast2.sh #!/bin/bash OUTFILE=/root/outfile INFILE=/root/infile function while_read_in_out { >$OUTFILE exec 3<&0 exec 0<$INFILE exec 4<&1 exec 1>$OUTFILE while read LINE do echo "$LINE" : done exec 1<&4 exec 4>&- exec 0<&3 exec 3>&- } while_read_in_out [root@pacteralinux shellscript]# ./proctextfast2.sh
次快
o[root@pacteralinux shellscript]# more proctextfast3.sh #!/bin/bash OUTFILE=/root/outfile INFILE=/root/infile function while_read_line_bottom_FD_OUT { >$OUTFILE exec 4<&1 #Associate standard output with file descriptor 4 exec 1>$OUTFILE #redirect standard output to $OUTFILE for LINE in $(cat $INFILE) #for LINE in `cat $INFILE` do echo $LINE : done exec 1<&4 exec 4>&- #restore standard output and close file descriptor 4 } while_read_line_bottom_FD_OUT
不使用文件描述符的情况下文件处理的最快方法
[root@pacteralinux shellscript]# cat proctextfast4.sh #!/bin/bash OUTFILE=/root/outfile INFILE=/root/infile function while_read_line_bottom_FD_OUT { >$OUTFILE while read LINE do echo $LINE>>$OUTFILE : done<$INFILE } while_read_line_bottom_FD_OUT
当infile是个命令时:
[root@pacteralinux shellscript]# vi proctextfast5.sh #!/bin/bash OUTFILE=/root/outfile INFILE=/root/infile function while_read_line_bottom_FD_OUT { >$OUTFILE while read LINE do echo $LINE>>$OUTFILE : done< <(date) # < <之间有空格 } while_read_line_bottom_FD_OUT ~
[root@pacteralinux ~]# more outfile Fri Dec 13 16:43:08 CST 2013
24:邮件通知技术
在发生错误,任务结束,或者需要时发送通知给用户时一个很好的做法!
mail mailx
mail -r uset@hostname -s "subject" $MAILOUT_LIST < $MAIL_FILE
cat $MIAL_FILE | mail -r uset@hostname -s "subject" $MAILOUT_LIST
mail换成mailx用法相同
使用sendmail来发送外发邮件
sendmail -f uset@hostname -s "subject" $MAILOUT_LIST < $MAIL_FILE
25:创建进度指示器
一条小圆点:
[root@pacteralinux shellscript]# vi processbar.sh #!/bin/bash while : do echo -n "." sleep 1 done
一条旋线