301# 注释2:<<EOF,冒号在shell中也是命令,表示什么都不做。3echo "I am oldboy"4echo "I am oldboy"5echo "I am oldboy"6EOF #必须顶格写7
8# 井号作为注释9在目前的Linux中用bash和sh都是一样的,因为sh是bash的软连接。10
11shell脚本的执行121. bash script-name132. path/to/script-name或./script-name143. source script-name或. script-name154. sh<script-name或cat script-name|sh16
17bash script_name # 新开启一个子shell18.或者source # 不会新开一个子shell19
20bash脚本的一些规范化建议:211.开头加脚本解释器222.附带作者及版权信息233.脚本扩展名为*.sh244.脚本存放在固定的目录下255.脚本中不用中文266.成对的符号一次书写完成277.循环格式一次性输入完成28
29登录shell:优先/etc/profile,然后加载~/.bash_profile ,再次加载~/.bashrc,最后加载/etc/bashrc30非登录shell:/etc/bashrc,~/.bashrc在执行一个非登录shell时调用
登录shell:优先/etc/profile,然后加载~/.bash_profile ,再次加载~/.bashrc,最后加载/etc/bashrc
非登录shell:/etc/bashrc,~/.bashrc在执行一个非登录shell时调用
变量
xxxxxxxxxx301定义环境变量2export TEST=13TEST=14export TEST5declare -x TEST=16
7shell变量的使用和命名规范建议:8针对变量名:(一般驼峰法则或者是下划线分隔都行)91)变量名的定义要有一定的命令规范,并且要见名知意102)变量名仅能使用字母,数字,下划线中的任意多个字符,并且以字母开头11针对变量内容:123)在脚本汇总定义普通字符串变量,精良把变量的内容用双引号括起来134)单独数字的变量内容可以不加引号145)希望变量的内容原样输出要加单引号156)希望变量的值应用命令并获取命令的结果就用反引号或${}16针对赋值符号:177)变量定义使用赋值符号=,赋值符号的两端不要有空格18针对变量输出:198)使用或者输出变量的内容,可用$变量名,例如echo $PATH209)拖用变量名db和面有其它字符连接的时候,就必须给变量名加上大括号{},如$db_t改为${db}_t21
22
23普通变量(局部变量)24当前用户或者脚本中生效,离开当前用户或者脚本就会失效。25变量的名称:遵循驼峰法则或者下划线分隔单词26变量内容:27变量名=value #<==不加引号。 ##解析变量或者命令,然后输出,纯数字选择不加引号。28变量名='value' #<==加单引号。 ###所见即所得29变量名="value" #<==加双引号。 ##解析变量或者命令,然后输出,字符串默认选择双引号,可以把要定义的内容作为一个整体。30变量名=`ls` 或变量名=$(ls)xxxxxxxxxx561# 变量引用和变量替换2`command_name_str` 反引号强引用,和$()等同var_name=`ls`3
4$(command_name_str) $(),命令置换 var_name=$(ls)5
6${var_name} 变量引用 ${var_name}_d7
8$var_name 变量引用 $var_name_d ≠ ${var_name}_d9
10
11位置变量 描述12$0 脚本的路径或名称13$n n的范围是0~9,表示传入的第n个参数的值14$# 脚本中传入参数的个数15$* 传入的所有参数,但合并为一个参数16$@ 传入的所有参数,不合并为一个参数17状态变量 描述18$? 上一次执行程序的返回结果19$$ 当前执行脚本的进程号20$! 获取上一个后台工作进程的进程号21$_ 获取上一个执行脚本的最后一个参数22
23
24变量子串 描述25${parameter} 返回变量的内容26${#parameter} 返回变量的长度,也适合特殊变量。27 echo ${#TEST}28 expr length "${TEST}"29 echo $TEST|awk '{print length ($0)}'30${parameter:offset} 从offset开始取字串到结尾31${parameter:offset:length} 从offset开始取length长度的字串32${parameter#word} 从变量开头开始删除最短匹配的word字串,可用通配符33${parameter##word} 从变量开头开始删除最长匹配的word字串,可用通配符34${parameter%word} 从变量结尾开始删除最短匹配的word字串,可用通配符35${parameter%%word} 从变量结尾开始删除最长匹配的word字串,可用通配符36${parameter/pattern/string} 使用string代替第一个匹配的pattern,可用通配符37${parameter//pattern/string} 使用string代替所有匹配的pattern,可用通配符38
39# shell特殊变量扩展(冒号可以省略) 40${parameter:-word} result=${var:-word}41 如果变量var值为空或未赋值,那么就把值word赋值给result,但是不复制给var变量42 find $path -name "*.log" -mtime +7 | xargs rm -rf43 find ${path:-/tmp} -name "*.log" -mtime +7 | xargs rm -rf44 典型应用:httpd的启动脚本45
46${parameter:=word} result=${var:-word}47 如果变量var值为空或未赋值,那么就把值word赋值给result,然后再赋值给变量var48
49
50${parameter:?word} result=${var:-word}51 如果变量var值为空或未赋值,那么就把值word当做bash错误提示输出52 -bash: var:word53
54${parameter:+word} result=${var:-word}55 如果变量var值为空或未赋值,那么无操作,如果变量var不为空,就把值赋值给result,但是不赋值给var变量56
运算符号
xxxxxxxxxx141常见的运算符 描述2+、- # 加法、减法3*、/、% # 乘法、除法、取余(模)4** # 幂运算5++、-- # 增加或减少,前置和后置表达式的结果是不一样的6!、&&、|| # 逻辑非、逻辑与、逻辑或7<、<=、>、>= # 小于、小于等于、大于、大于等于8==、!=、= # 相等、不相等、对于字串可表示相当9<<、>> # 左移位、右移位10~、&、|、^ # 按位取反、按位与、按位或、安慰异或11=、+=、-=、*=、/=、%= # 赋值、增强赋值12 # 在强类型语言(Java)中,a+=b和a=a+b是有区别的,13 # 他们的区别是:在处理过程中各自数据类型有转换,a+=b<=>a=(a+b),它是做了数据类型强制转换的14
运算方法
xxxxxxxxxx371shell中常用的数学运算方法 描述2(()) 整数计算,效率高3let 整数运算,类似(())4expr 可用于整数运算,但是还有很多其它的功能5bc 适合整数和小数运算6$[] 整数计算7awk 适合整数和小数运算8 echo 2.1 1.4|awk '{print $1*$2}'9declare 定义变量值和属性,-i参数用于定义整型变量,做运算10 declare -i a=4+511 12表达式 描述13$(i=i+1) 运算后赋值,即将i+1的运算结果复制给变量i。注意不能用echo ((i=i+1))来输出表达式的值,但是可以用echo $((i=i+1))来输出。14i=$((i+)) 可以在(())前加$符号,将表达式运算后复制给i15((8>7&&5==5)) 可以进行比较运算,还可以加入逻辑与和逻辑或,用于条件判断16echo $((2+1)) 需要直接输出运算表达式结果时可以在(())前面加上$符号17
18
19expr判断一个变量是否为整数2021expr 2 + $1 &>/dev/null22if [ $? -eq 0 ];then23 echo "$1 is integer"24else25 echo "$1 is not integer"26fi27
28判断扩展名2930expr "$1" : ".*\.txt" &>/dev/null31if [ $? -eq 0 ];then32 echo "file extension is txt"33else34 echo "file extension not is txt"35fi36计算字符长度37expr length "str"用户交互
xxxxxxxxxx5312a=$13b=$24echo "a-b=$(($a-$b))"5echo "a+b=$(($a+$b))"6echo "a*b=$(($a*$b))"7echo "a/b=$(($a/$b))"8echo "a**b=$(($a**$b))"9echo "a%b=$(($a%$b))"10
11-p 提示12-t 等待用户输入的时间13read -t 30 -p "请输入一个数字:"1415read -p "请输入两个数字:" a b16echo "a-b=$(($a-$b))"17echo "a+b=$(($a+$b))"18echo "a*b=$(($a*$b))"19echo "a/b=$(($a/$b))"20echo "a**b=$(($a**$b))"21echo "a%b=$(($a%$b))"22
2324cat <<EOF25 1.install lamp26 2.install lnmp27 3.exit28EOF29read -p "请选择一个序号(必须是数字):" num30#1.判断是否为整数31expr 2 + $num &>/dev/null32if [ $? -ne 0 ]33then34 echo "Usage:$0 {1|2|3}"35 exit 136fi37
38#2.判断执行处理39if [ $num -eq 1 ]40then41 echo "install lamp..."42elif [ $num -eq 2 ]43then44 echo "install lnmp..."45elif [ $num -eq 3 ]46then47 echo "bye."48 exit 49else50 echo "Usage:$0 {1|2|3}"51 exit 152fi53
条件测试
xxxxxxxxxx1331条件表达式6种写法:if,while2 语法1: test <测试表达式>3 语法2: [ <测试表达式> ] #两端有空格4 语法3:[[ <测试表达式> ]] #两端有空格5 语法4:((<测试表达式>)) #不需要空格6
7 语法5:(命令表达式) 8 语法6:`命令表达式`9
10编程语法:11[ <测试表达式> ] && 命令112如果前面表达式成功,那么就执行后面命令。13
14[ <测试表达式> ] || 命令115如果前面表达式失败,那么就执行后面命令。16
17[ <测试表达式> ] && {18命令119命令220命令321}22如果前面表达式成功,那么就执行后面命令。23
24[ <测试表达式> ] && 命令1 || 命令225如果前面表达式成功,那么就执行命令1,否则执行命令2。26
27[ <测试表达式> ] && {28命令129命令230}||{31命令332命令433}34如果前面表达式成功,那么就执行命令1,2,否则执行命令3,4。35
36
37常用文件测试表达式 描述38-d 文件,directory 39-f 文件,file 40-e 文件,exist 41-r 文件,read 42-s 文件,size 43-w 文件,write 44-x 文件,executable 45-L 文件,link 46f1 -nt f2,newer than 47其它内容可以直接man test 查找。48
49
50在[]以及test中使用 在(())和[[]]中使用 描述51-eq ==或= equal,等于52-ne != not equal,不等于53-gt > greater than,大于54-ge >= greater equal,大于等于55-lt < less than,小于56-le <= less equal,小于等于57
58注:[ ]是比较老旧的写法,[[ ]]是比较新的用法,它支持[ ]中的写法59
60字符串测试表达式61[ -n "字符串" ] 字符串长度[不]为0,表达式为真。 not zero。62[ -z "字符串" ] 字符串长度为0,表达式为真。 zero。63[ "字符串1" == "字符串2" ] 两个字符串相同则为真。64[ "字符串1" !== "字符串2" ] 两个字符串不相同则为真。65
6667read -p "pls input two num:" a b68
69if [ -z "$b" ]70then71 echo "请输入两个数"72 exit 173fi74expr $a + $b + 1 &>/dev/null75if [ $? -ne 0 ]76then77 echo "Usage:$0 num1 num2"78 exit 179fi80
81
8283read -p "please input two integer number." a b84
85[ -z "$b" ] &&{86 echo "please input two integer number."87 exit 188}89
90expr $a + $b + 1 &>/dev/null91[ $? -ne 0 ] &&{92 echo "please input two integer number."93 exit 294}95
96if [ $a -gt $b ];then97 echo "$a>$b"98 exit 099elif [ $a -eq $b ];then100 echo "$a=$b"101 exit 0102else103 echo "$a<$b"104 exit 0105fi106
107
108在[ ]和test中 在[[]]和(())中 描述109-a && and,与110-o || or,或111! ! not,非112注:[ ]是比较老旧的写法,[[ ]]是比较新的用法,它支持[ ]中的写法113[] [[]] (()) 这些符号之间连接 使用&& ||114
115
116+-----------------+----------------+------------------+-----------------+-------------------+117| 条件表达式符号 [] test [[]] (())118+-----------------+----------------+------------------+-----------------+-------------------+119| 边界是否需要空格 需要 需要 需要 不需要120+-----------------+----------------+------------------+-----------------+-------------------+121| 逻辑操作符 !、-a、-o !、-a、-o !、&&、|| !、&&、||122+-----------------+----------------+------------------+-----------------+-------------------+123| 整数比较操作符 -eq、-gt -eq、-gt -eq、-gt =、>、<124| -lt、-ge -lt、-ge -lt、-ge、-le >=、<=125| -le -le 或126| =、>、<127| >=、<=128+-----------------+----------------+------------------+-----------------+-------------------+129| 字符串比较操作符 =、==、!= =、==、!= =、==、!= =、==、!=130+-----------------+----------------+------------------+-----------------+-------------------+131| 是否支持通配符 不支持 不支持 支持 不支持132+-----------------+----------------+------------------+-----------------+-------------------+133

vim配置
xxxxxxxxxx681set nocompatible 2set history=1003filetype on4filetype plugin on5filetype indent on 6set autoread 7set mouse=c8syntax enable 9set cursorline10hi cursorline guibg=#00ff0011hi CursorColumn guibg=#00ff0012set foldenable13set foldmethod=manual14set foldcolumn=015setlocal foldlevel=316set foldclose=all 17nnoremap <space> @=((foldclosed(line('.')) < 0) ? 'zc' : 'zo')<CR>18set expandtab19set tabstop=420set shiftwidth=421set softtabstop=422set smarttab23set ai 24set si 25set wrap 26set sw=4 27set wildmenu 28set ruler 29set cmdheight=1 30set lz 31set backspace=eol,start,indent 32set whichwrap+=<,>,h,l 33set magic 34set noerrorbells35set novisualbell36set showmatch 37set mat=4 38set hlsearch39set ignorecase40set encoding=utf-841set fileencodings=utf-842set termencoding=utf-843set smartindent44set cin45set showmatch46set guioptions-=T47set guioptions-=m48set vb t_vb=49set laststatus=450set pastetoggle=<F9>51set background=dark52highlight Search ctermbg=black ctermfg=white guifg=white guibg=black53autocmd BufNewFile *.py,*.cc,*.sh,*.java exec ":call SetTitle()"54func SetTitle() 55 if expand("%:e") == 'sh' 56 call setline(1, "#!/bin/bash")57 call setline(2, "##############################################################") 58 call setline(3, "# File Name: ".expand("%"))59 call setline(4, "# Version: V1.0")60 call setline(5, "# Author: meizy")61 call setline(6, "# Organization: ")62 call setline(7, "# Contact: [email protected]")63 call setline(8, "# Created Time : ".strftime("%F %T"))64 call setline(9, "# Description:")65 call setline(10, "##############################################################")66 endif 67endfunc68
流程控制语句语法
xxxxxxxxxx2231if statement2if <condition>;then3 statement4fi5if <condition>;then6 statement7else8 statement9fi10if <condition>;then11 statement12elif <condition>;then13 statement14elif <condition>;then15 statement16...17else18 statement19fi20
21例1:如果不存在/backup目录就创建。22考查if单分支23例2:开发Shell脚本判断系统剩余内存的大小,如果低于100MB就提示内存不足,否则提示内存充足。24例3:分别使用变量定义、read读入及脚本传参方式实现比较2个整数的大小。25例4:打印一个菜单如下,当用户选择对应的数字时,就执行对应项的应用。26 1.install lamp27 2.install lnmp28 3.exit29
3031cat <<EOF32 1.install lamp33 2.install lnmp34 3.exit35EOF36read -p "请选择一个序号(必须是数字):" num37#1.判断是否为整数38expr 2 + $num &>/dev/null39if [ $? -ne 0 ]40then41 echo "Usage:$0 {1|2|3}"42 exit 143fi44
45#2.判断执行处理46if [ $num -eq 1 ]47then48 echo "install lamp..."49elif [ $num -eq 2 ]50then51 echo "install lnmp..."52elif [ $num -eq 3 ]53then54 echo "bye."55 exit 56else57 echo "Usage:$0 {1|2|3}"58 exit 159fi60
61# case语句62case statement63case variable in64 value1)65 statement66 ;;67 value2)68 statement69 ;;70 ...71 valuen)72 statement73 ;;74 *)75 statement76 ;; #这里可以省略,前面都不可以省略77esac78
7980cat <<EOF-811.apple822.pear833.banana844.cherry85 EOF86
87
8889cat <<EOF901.apple912.pear923.banana934.cherry94EOF95
9697cat <<'EOF'98$PATH99EOF100
101102cat <<EOF103$PATH104EOF105
106
107rsyncd启动脚本108
109110start(){111 rsync --daemon112 retval=$?113 if [ $retval -eq 0 ]114 then115 echo "rsync startup ok"116 return $retval117 else118 echo "rsync startup fail"119 return $retval120 fi121}122stop(){123 killall rsync124 retval=$?125 if [ $retval -eq 0 ]126 then127 echo "rsync stop ok"128 return $retval129 else130 echo "rsync stop fail"131 return $retval132 fi133}134case "$1" in135 start)136 start137 retval=$?138 ;;139 stop)140 stop141 retval=$?142 ;;143 restart)144 stop145 sleep 1146 start147 retval=$?148 ;;149 *)150 echo "usage:$0 {start|stop|restart}"151 exit 1152esac153exit $retval154
155输出内容时可以调用系统函数库156157. /etc/init.d/functions158action "service starting " /bin/ture159action "service staring" /bin/false160
161rsyncd启动脚本162163. /etc/init.d/functions164lockfile=/var/lock/subsys/rsyncd165rsyncd_pid_file_path=/var/run/rsyncd.pid166
167start(){168 rsync --daemon169 retval=$?170 if [ $retval -eq 0 ]171 then172 action "rsync startup" /bin/true173 touch $lockfile174 return $retval175 else176 action "rsync startup" /bin/false177 return $retval178 fi179}180stop(){181 if test -s "$rsyncd_pid_file_path";then182 rsyncd_pid=`cat $rsyncd_pid_file_path`183 if (kill -0 $rsyncd_pid &>/dev/null);then # pid对应的进程是否真实存在184 kill $rsyncd_pid185 rm -f $lockfile >/dev/null186 retval=$?187 if [ $retval -eq 0 ]188 then189 action "rsync stop" /bin/true190 return $retval191 else192 action "rsync stop" /bin/false193 return $retval194 fi195 else196 echo "rsyncd process is no exists."197 return 2198 fi199 else200 echo "$rsyncd_pid_file_path is not exists,or rsyncd not start."201 fi202}203case "$1" in204 start)205 start206 retval=$?207 ;;208 stop)209 stop210 retval=$?211 ;;212 restart)213 stop214 sleep 1215 start216 retval=$?217 ;;218 *)219 echo "usage:$0 {start|stop|restart}"220 exit 1221esac222exit $retval223
xxxxxxxxxx1101for statement syntax2for variable in list3do4 statement5done6for ((控制变量初始化;条件判断表达式;控制变量的修正表达式))7do8 statement9done10
11获取列表12(1) 直接给出列表;13(2) 整数列表:14(a) {start..end}15(b) $(seq [start [step]] end) 16(3) 返回列表的命令;17$(COMMAND)18(4) glob 通配的方式19(5) 变量引用;20$@, $*21 22 23 #!/bin/bash24 for((j=1;j<=9;j++));do25 for((i=1;i<=j;i++))do26 echo -e -n "${i}X${j}=$[$i*$j]\t"27 done 28 echo 29 done30 31将文件中的finished去掉32 准备文件touch stu_{1..10}_finished.jpg33 34 ls *.jpg|awk -F "_finished" '{print "mv",$0,$1$2}'|bash35 36 rename "_finished" "" *.jpg #rename to file37 38 #!/bin/bash39 for file in `ls ./*.jpg`40 do41 mv $file `echo ${file/_finished/}`42 done43信号编号 短名称 定义441 HUP 挂起452 INT 键盘中断463 QUIT 键盘退出479 KILL 中断(无法拦截4815 TERM 终止4918 CONT 继续5019 STOP 停止(无法拦截)5120 TSTP 键盘停止52note:先用SIGTERM 再用 SIGKILL 以避免SIGKILL可能造成的误用53
54
55sh while1.sh &56
57把脚本while1.sh放到后台执行(后台运行脚本时常用)*58
59nohup while1.sh &60
61使用nohup把脚本while1.sh放到后台执行,但消息会输出到标准输出62
63ctl+c64
65停止执行当前脚本或任务66
67ctl+z68
69暂停执行当前脚本或任务70
71bg72
73把当前脚本或任务放到后台执行,bg可以理解为background74
75fg76
77把当前脚本或任务拿到前台执行,如果有多个任务,可以使用fg加任务编号调出对应脚本任务,如fg 2,调出第二个脚本任务,fg可以理解为frontground78
79jobs80
81查看当前执行的脚本或任务82
83kill84
85关闭执行的脚本任务,即以“kill %任务编号”的形式关闭脚本,这个任务编号,可以通过jobs获得86
87
88常用进程管理命令89
90后台运行 &、nohup、screen(运维人员)91
92l kill、killall、pkill:杀掉进程。93l ps:查看进程。94l pstree:显示进程状态树。95l top:显示进程。96l renice:改变优先权。 97l nohup:用户退出系统之后继续工作。98l pgrep:查找匹配条件的进程。99l strace:跟踪一个进程的系统调用情况。100l ltrace:跟踪进程调用库函数的情况。101
102
103nohup和&U区别104
105no hangup的缩写,意即“不挂断”, 忽略所有挂断(SIGHUP)信号,不挂断的运行,注意没有后台运行功能,用nohup运行命令可以使命令永久的执行下去,和用户终端没有关系,例如我们断开SSH连接都不会影响他的运行,注意了nohup没有后台运行的意思;&才是后台运行。&是指在后台运行,但当用户退出(挂起)的时候,命令自动也跟着退出,那么把nohup和&结合起来用nohup COMMAND &这样就能使命令永久的在后台执行106
107&:放入后台,当session断掉,会受到SIGHUP信号,直接关闭,Ctrl+C无法关闭,输出会放到前台。108nohup:nohup: ignoring input and appending output to ‘nohup.out’,Ctrl+C程序收到SIGINT信号后,直接关闭,session断掉进程会自动把进程ID为1的进程当做父进程仍然运行,输出不会放到前台,。109nohup和&:键入Ctrl + C,发送SIGINT信号和关闭session,发送SIGHUP信号都不能关闭。110
xxxxxxxxxx751while condition|true|false while read line2do do3 statement statement4done done < /path/to/filename5
6cat /path/to/filename | while read line exec </path/to/filename7do while read line8 statement do9done statement10这里会开启一个子shell,所以while外无法使用while中处理的变量。 done1112 #13 read -p "Enter a user name: " username14 15 while true; do16 if who | grep "^$username" &> /dev/null; then17 break 18 fi19 sleep 320 done21 22 echo "$username logged on." >> /tmp/user.log23 24 #!/bin/bash25 read -p "Enter a option: " option26 while [ "$option" != 'cpu' -a "$option" != 'mem' -a "$option" != 'disk' -a "$option" != 'quit' ]; do27 read -p "Wrong option, Enter again: " option28 done29 30 #!/bin/bash31 while read line;do32 if [ $[`echo $line | cut -d: -f3` % 2] -eq 0 ];then33 echo -e -n "username: `echo $line | cut -d: -f1`\t" 34 echo "uid: `echo $line | cut -d: -f3 `"35 fi36 done < /etc/passwd37 38 #!/bin/sh39 while true 40 do41 uptime >>/tmp/uptime.log42 sleep 2 # usleep微妙43 done44 45 46猜数字游戏。首先让系统随机生成一个数字,给这个数字定一个范围(1-60),让用户输入猜的数字,对输入进行判断,如果不符合要求,就给予高或低的提示,猜对后则给出猜对用的次数,请用while语句实现。47提示:可以赋予一个猜水果的价格游戏。48分析:491)给这个数字定一个范围(1-60)50 echo $((RANDOM%60)) 执行脚本后是固定的,例如;5051 522)read -p "输入猜数字:" num53用户输入的数字和已知的随机数比较。54 553)连续猜就需要用while56 random="$((RANDOM%60))"57 count=058 while true59 do60 ((count++))61 read -p "请猜数字:" num62 if [ $num -gt $random ]63 then64 echo "猜高了。"65 elif [ $num -eq $random ]66 then67 echo "牛啊,猜对了,一共猜了${count}次。"68 exit69 else70 echo "猜低了。"71 fi72 done73 74Apache访问日志(access_2010-12-8.log),把日志中每行的访问字节数对应字段数字相加,计算出总的访问量。给出实现程序,请用while循环实现。(3分钟)75
xxxxxxxxxx281 until statement syntax2until condition|true|false3do4 statement5done67#8declare -i j=19declare -i i=110 11until [ $j -gt 9 ]; do12 until [ $i -gt $j ]; do 13 echo -n -e "${i}X${j}=$[$i*$j]\t"14 let i++15 done16 echo17 let i=118 let j++19done20 2122#23read -p "Enter a user name: " username24 25until who | grep "^$username" &> /dev/null; do26 sleep 327done28
select
xxxxxxxxxx621select statement2select variable in list3do4 statement5done67echo "Which car do you prefer?"8select CAR in Benz Audi VolksWagen9do10 break11done12echo "You chose $CAR"13 14 1516select DAY in Mon Tue Wed Thu Fri Sat Sun17do18 case $DAY in19 Mon)20 echo "Today is Monday";;21 Tue)22 echo "Today is Tuesday";;23 Wed)24 echo "Today is Wednesday";;25 Thu)26 echo "Today is Thursday";;27 Fri)28 echo "Today is Friday";;29 Sat|Sun)30 echo "You can have a rest today";;31 *)32 echo "Unknown input ,exit now" && break;;33 esac34done35
36
37
38 命令 说明39break n 如果省略n表示跳出整个循环,n 表示跳出循环的层数40continue n 如果省略n表示跳过本次循环,忽略本次循环的剩余代码,进入循环的下一次循环。n 表示退到第n层继续循环41exit n 退出当前shell程序,n为上一次程序执行的状态返回值。n也可以省略,再下一个shell里可通过$?接收exit n的n值42return n 用于在函数里,作为函数的返回值,用于判断函数执行是否正确。再下一个shell里可通过$?接收exit n的n值43
44break[n]和continue[n]都是在循环语句中使用,break 结束整个循环,continue退出当次循环,进入下次循环。45 4647#48declare -i i=049declare -i sum=050 51until [ $i -gt 100 ]; do52 let i++53 if [ $[$i%2] -eq 1 ]; then54 continue 55 fi56 let sum+=$i 57done58 59echo "Even sum: $sum"60 61break、continue在条件语句及循环语句(for、while、if等)中用于控制程序的走向,而exit则用于终止所有语句并退出当前脚本,除此之外,exit还可以返回上一次程序或命令的执行状态值给当前Shell;return类似exit,只不过return仅用于在函数内部返回函数执行的状态值。62
xxxxxxxxxx1241是函数的返回值,它返回值给调用者。2
3函数调用和传参45function test(){6 local name="test" #仅在函数内生效7 id="id_test" # 在函数内外都生效,不建议使用8 echo "The test function \$1 is $1" #这里的$1是传入函数的参数9 return 110}11
12# 函数一定要先定义后调用13test args14test $1 #这里的$1是传入脚本的参数15echo $? # 获取函数return的值16echo ${id}17# echo ${name} #获取不到18
19其它脚本中调用函数2021. /path/to/func_filename22source /path/to/func_filename23test args24test $1 #这里的$1是传入脚本的参数25
26
27企业案例:通过脚本传参的方式,检查Web 网站URL是否正常。28wget命令:29 --spider 模拟爬虫30 -q 安静访问31 -o /dev/null 不输出32 -T --timeout 超时时间33 -t --tries 重试次数34~]# wget --spider -T 5 -q -o /dev/null -t 2 www.baidu.com35~]# echo $?36037curl命令:38 -I 看响应头39 -s 安静的40 -o /dev/null 不输出41 -w %{http_code} 返回状态码,20042 -m 超时时间43
44~]# curl www.baidu.com -s &>/dev/null45~]# echo $?46047~]# curl -I -m 5 -s -w "%{http_code}\n" -o /dev/null www.baidu.com4820049
50
51不用函数的实现写法5253if [ $# -ne 1 ]54 then55 echo $"usage:$0 url"56 exit 157fi58wget --spider -q -o /dev/null --tries=1 -T 5 $1 #<==-T指定超时时间,这里的$1为脚本的参数。59if [ $? -eq 0 ]60 then61 echo "$1 is yes."62else63 echo "$1 is no."64fi65高端专业的函数写法:66
67cat checkurl.sh 6869##############################################################70# File Name: checkurl.sh71# Version: V1.072# Author: oldboy73# Organization: www.oldboyedu.com74# Created Time : 2018-06-07 18:29:1975# Description:76##############################################################77usage(){78 echo "Usage:$0 url"79 exit 180}81checkurl(){82 wget -q -o /dev/null -t 2 -T 5 $183 if [ $? -eq 0 ]84 then85 echo "$1 is ok"86 else87 echo "$1 is fail"88 fi89}90main(){91 if [ $# -ne 1 ]92 then93 usage94 fi95 checkurl $196}97main $*98
99[root@oldboy scripts]# cat 8_5_1.sh 100101function usage() { #<==帮助函数102 echo $"usage:$0 url"103 exit 1104}105
106function check_url() { #<==检测URL函数。107 wget --spider -q -o /dev/null --tries=1 -T 5 $1 #<==这里的$1就是函数传参。108 if [ $? -eq 0 ]109 then110 echo "$1 is yes."111 else112 echo "$1 is no."113 fi114}115
116function main() { #<==主函数。117 if [ $# -ne 1 ] #<==如果传入的多个参数,则打印帮助函数,提示用户。118 then119 usage120 fi121 check_url $1 #<==接收函数的传参,即把结尾的$*传到这里。122}123main $* #<==这里的$*就是把命令行接收的所有参数作为函数参数传给函数内部,常用手法。124
array
xxxxxxxxxx501Shell数组的定义2Shell数组的定义有多种方法,列举如下。3方法1:用小括号将变量值括起来赋值给数组变量,每个变量值之间要用空格分隔。4语法如下:5array=(value1 value2 value3 ... ) 6此为常用定义方法,需重点掌握。7示例如下:8~]# array=(1 2 3) #<==用小括号将数组内容赋值给数组变量,数组元素用“空格”分隔开。9~]# echo ${array[*]} #<==输出上面定义的数组的所有元素值,注意语法。101 2 311方法2:用小括号将变量值括起来,同时采用键值对的形式赋值。12语法如下:13array=([1]=one [2]=two [3]=three) 14此种方法为key-value键值对的形式,小括号里对应的数字为数组下标,等号后面的内容为下标对应的数组变量的值,此方法比较复杂,不推荐使用。15示例如下:16~]# array=([1]=one [2]=two [3]=three)17~]# echo ${array[*]} #<==输出上面定义的数组的所有元素值。 18one two three19~]# echo ${array[1]} #<==输出上面定义的数组的第一个元素值。20one21~]# echo ${array[2]} #<==输出上面定义的数组的第二个元素值。22two23~]# echo ${array[3]} #<==输出上面定义的数组的第三个元素值。24three25方法3:通过分别定义数组变量的方法来定义。26语法如下:27array[0]=a;array[1]=b;array[2]=c28此种定义方法比较麻烦,不推荐使用。29示例如下:30~]# array[0]=a31~]# array[1]=b32~]# array[2]=c33~]# echo ${array[0]}34a35方法4:动态地定义数组变量,并使用命令的输出结果作为数组的内容。36语法为:37array=($(命令))38或39array=(`命令`)40示例如下:41data]# mkdir /array/ -p42data]# touch /array/{1..3}.txt43data]# ls /array/441.txt 2.txt 3.txt45data]# array=($(ls /array))46data]# echo ${array[*]}471.txt 2.txt 3.txt48说明:还可以使用declare -a array来定义数组类型,但是比较少这样用。49
50
xxxxxxxxxx1501Shell数组的打印及输出21. 打印数组元素3此为常用知识点,需重点掌握。示例如下:4data]# array=(one two three)5data]# echo ${array[0]}6#<==打印单个数组元素用${数组名[下标]},当未指定数组下标时,数组的下标是从0开始。7one8data]# echo ${array[1]}9two10data]# echo ${array[2]}11three12data]# echo ${array[*]} #<==使用*或者@可以得到整个数组内容。13one two three14data]# echo ${array[@]} #<==使用*或者@可以得到整个数组内容。15one two three162. 打印数组元素的个数17此为常用知识点,需重点掌握。示例如下:18data]# echo ${array[*]} #<==使用*或者@可以得到整个数组内容。19one two three20data]# echo ${#array[*]} #<==用${#数组名[@或*]}可以得到数组长度,这和前文讲解的变量子串知识是一样的,因为数组也是变量,只不过是特殊的变量,因此也适合变量的子串替换等知识。21322data]# echo ${array[@]} #<==使用*或者@可以得到整个数组内容。23one two three24data]# echo ${#array[@]} #<==用${#数组名[@或*]}可以得到数组长度,这和前文讲解的变量子串知识是一样的,因为数组也是变量,只不过是特殊的变量,因此也适合变量的子串替换等知识。253263. 数组赋值27此知识不常用,了解即可。可直接通过“数组名[下标] ”对数组进行引用赋值,如果下标不存在,自动添加新一个数组元素,如果下标存在就覆盖原来的值。28示例如下:29data]# array=(one two three)30data]# echo ${array[*]}31one two three32data]# array[3]=four #<==增加下标为3的数组元素。33data]# echo ${array[*]}34one two three four35data]# array[0]=oldboy36data]# echo ${array[*]}37oldboy two three four38~]# array[0]=mei #<==修改数组元素。39~]# echo ${array[@]}40mei 2 3 4414. 数组的删除42因为数组本质上还是变量,因此可通过“unset 数组[下标]”清除相应的数组元素,如果不带下标,表示清除整个数组的所有数据。43示例如下:44data]# echo ${array[*]}45oldboy two three four46data]# unset array[1] #<==取消下标为1的数组元素。47data]# echo ${array[*]} #<==打印输出后发现数组元素“two”,不见了。48oldboy three four49data]# unset array #<==删除整个数组。50data]# echo ${array[*]}51#<==没有任何内容了。525. 数组内容的截取和替换53这里和前文变量子串的替换是一样的,因为数组是特殊的变量。数组元素部分内容截取的示例如下:54~]# array=(1 2 3 4 5)55~]# echo ${array[@]:1:3} #<==从下标为1的元素开始截取,共取3个数组元素。562 3 457data]# array=({a..z}) #<==将变量的结果赋值给数组变量。58data]# echo ${array[@]}59a b c d e f g h i j k l m n o p q r s t u v w x y z60data]# echo ${array[@]:1:3} #<==从下标为1的元素开始截取,共取3个数组元素。61b c d62data]# echo ${array[@]:0:2} #<==从下标为0的元素开始截取,共取2个数组元素。63a b64数组元素部分内容的替换如下:65data]# array=(1 2 3 1 1) 66data]# echo ${array[@]/1/b} #<==把数组中的1替换成b,原数组未被修改,和sed很像。67b 2 3 b b68提示:调用方法是:${数组名[@或*]/查找字符/替换字符} 该操作不会改变原先数组内容,如果需要修改,可以看上面例子,重新定义数组。69数组元素部分内容的删除如下:70data]# array=(one two three four five)71data]# echo ${array[@]} 72one two three four five73data]# echo ${array[@]#o*} #<==从左边开始匹配最短的,并删除。 74ne two three four five75data]# echo ${array1[@]##o*} #<==从左边开始匹配最长的,并删除。 76two three four five77data]# echo ${array[@]%f*} #<==从右边开始匹配最短的,并删除。 78one two three79data]# echo ${array[@]%%f*} #<==从右边开始匹配最长的,并删除。80one two three81提示:数组也是变量,因此也适合于前面讲解过的变量的子串处理的功能应用。82数组的其他相关知识通过man bash然后搜Arrays来了解。83
84
85范例:使用循环批量输出数组的元素。86方法1:通过C语言型的for循环语句打印数组元素。8788array=(1 2 3 4 5)89for((i=0;i<${#array[*]};i++)) #<==从数组的第一个小标0开始,循环数组的所有下标。90do91 echo ${array[i]} #<==打印数组元素。92done93方法2:通过普通for循环语句打印数组元素。9495array=(1 2 3 4 5)96for n in ${array[*]} #<==${array[*]}表示输出数组所有元素,相当于列表数组元素。97do98 echo $n #<==这里就不是直接去数组里取元素了,而是变量n的值。99done100输出结果同方法1,此处略过。101方法3:使用while循环语句打印数组元素。102103array=(1 2 3 4 5)104i=0105while ((i<${#array[*]}))106do107 echo ${array[i]}108 ((i++))109done110输出结果同方法1,此处略过。111
112范例:通过竖向列举法定义数组元素并批量打印。113114array=( #<==对于元素特别长的时候,例如URL地址,竖向列出来看起来舒服和规范。115 oldboy116 oldgirl117 xiaoting118 bingbing119)120for ((i=0; i<${#array[*]}; i++))121do122 echo "This is num $i,then content is ${array[$i]}"123done124echo ----------------------125echo "array len:${#array[*]}"126输出结果如下:127This is num 0,then content is oldboy128This is num 1,then content is oldgirl129This is num 2,then content is xiaoting130This is num 3,then content is bingbing131----------------------132array len:4133范例:把命令结果作为数组元素定义并打印。134准备数据:135scripts]# mkdir -p /array/136scripts]# touch /array/{1..3}.txt137scripts]# ls /array/1381.txt 2.txt 3.txt139以下为开发脚本:140141dir=($(ls /array)) #<==把ls /array命令结果放数组里。142for ((i=0; i<${#dir[*]}; i++)) #<==${#dir[*]}为数组的长度。143do144 echo "This is NO.$i,filename is ${dir[$i]}"145done146输出结果如下:147This is NO.0,filename is 1.txt148This is NO.1,filename is 2.txt149This is NO.2,filename is 3.txt150
xxxxxxxxxx331(1)定义命令2静态数组:3array=(1 2 3)4动态数组:5array=($(ls))或array=(`ls`)6给数组赋值:7array[3]=48(2)打印命令9打印所有元素:10${array[@]}或${array[*]}11打印数组长度:12${#array[@]}或${#array[*]}13打印单个元素:14${array[i]} #<==i是数组下标。15(3)循环打印的常用基本循环1617arr=(18 10.0.0.1119 10.0.0.2220 10.0.0.3321)22#C语言for循环语法23for ((i=0;i<${#arr[*]};i++))24do25 echo "${arr[$i]}"26done27echo ---------------28#普通for循环语法29for n in ${arr[*]}30do31 echo "$n"32done33
xxxxxxxxxx3911范例:利用bash for循环打印下面这句话中字母数不大于6的单词(某企业面试真题)。2I am oldboy teacher welcome to oldboy training class3解答思路:41)先把所有的单词放到数组里,然后依次进行判断。命令如下:5array=(I am oldboy teacher welcome to oldboy training class)62)对变量内容计算长度,这在前文已经讲解过了。常见方法有4种:7scripts]# char=oldboy8scripts]# echo $char|wc -L9610scripts]# echo ${#char}11612scripts]# expr length $char13614scripts]# echo $char|awk '{print length}'15616方法1:通过数组方法实现。17arr=(I am oldboy teacher welcome to oldboy training class)18for ((i=0;i<${#arr[*]};i++))19do 20 if [ ${#arr[$i]} -lt 6 ]21 then22 echo "${arr[$i]}"23 fi24done25echo -----------------------26for word in ${arr[*]}27do28 if [ `expr length $word` -lt 6 ];then29 echo $word30 fi31done32说明:本例给出了两种for循环语法打印数组元素的方法。33方法2:使用for循环列举取值列表法34for word in I am oldboy teacher welcome to oldboy training class #<==看起来有点low吧。35do36 if [ `echo $word|wc -L` -lt 6 ];then37 echo $word38 fi39done40
41chars="I am oldboy teacher welcome to oldboy training class" #<==定义字符串也可以。42for word in $chars43do44 if [ `echo $word|wc -L` -lt 6 ];then45 echo $word46 fi47done48方法3:通过awk循环实现。49scripts]# chars="I am oldboy teacher welcome to oldboy training class"50scripts]# echo $chars|awk '{for(i=1;i<=NF;i++) if(length($i)<=6)print $i}'51几种方法的输出结果统一为:52I53am54oldboy55to56oldboy57class58范例:批量检查多个网站地址是否正常 59要求:601)使用Shell数组方法实现,检测策略尽量模拟用户访问。612)每10秒钟做一次所有的检测,无法访问的输出报警。623)待检测的地址如下。63http://blog.oldboyedu.com64http://blog.etiantian.org65http://oldboy.blog.51cto.com66http://10.0.0.767解题思路:681)把URL定义成数组,形成函数。692)编写URL检查脚本函数,传入数组的元素,即URL。703)组合实现整个案例,编写main主函数(即执行函数),每隔10秒检查一次。71下面的参考答案采用了Shell数组方法,同时检测多个URL是否正常,并给出专业的展效果7273# this script is created by oldboy.74# e_mail:[email protected]75# function:case example76# version:1.377. /etc/init.d/functions78check_count=079url_list=( #<==定义检测的URL数组,包含多个URL地址。80http://blog.oldboyedu.com81http://blog.etiantian.org82http://oldboy.blog.51cto.com83http://10.0.0.784)85
86function wait() #<==定义3,2,1倒计时函数。87{88 echo -n '3秒后,执行检查URL操作.';89 for ((i=0;i<3;i++))90 do91 echo -n ".";sleep 192 done93 echo94}95function check_url() #<==定义检测URL的函数。96{97 wait #<==执行倒计时函数。98 for ((i=0; i<`echo ${#url_list[*]}`; i++)) #<==循环数组元素。99 do100 wget -o /dev/null -T 3 --tries=1 --spider ${url_list[$i]} >/dev/null 2>&1 #<==检测是否可以访问数组元素的地址。101 if [ $? -eq 0 ] #<==如果返回值为0,表示访问成功。102 then103 action "${url_list[$i]}" /bin/true #<==优美的显示成功结果。104 else105 action "${url_list[$i]}" /bin/false #<==优美的显示失败结果。106 fi107 done108 ((check_count++)) #<==检测次数加1。109}110main(){ #<==定义主函数。111 while true #<==开启一个持续循环。112 do113 check_url #<==加载检测url的函数。114 echo "-------check count:${check_count}---------"115 sleep 10 #<==间歇10秒。116 done117}118main #<==优美的显示成功结果,调用主函数运行程序。119执行结果如图所示。120检测数组内URL输出的专业效果图121提示:实际使用时,一些基础的函数脚本(例如:加颜色的函数)是放在函数文件里的(例如:放在/etc/init.d/functions里,与执行的脚本内容部分分离,看起来更清爽,大型的语言程序都是这样开发的),另外,特别注意wget命令后要接重试次数--tries参数,否则检查时会卡住。122
123范例:开发一个守护进程脚本,每30秒监控MySQL主从复制是否异常(包括不同步以及延迟),如果异常,则发送短信并发送邮件给管理员存档(此为生产实战案例)。124提示:如果没主从复制的环境,可以把下面的文本放到文件里读取来模拟主从复制状态:125*************************** 1. row ***************************126 Slave_IO_State: Waiting for master to send event127 Master_Host: 10.0.0.51 128 Master_User: rep129 Master_Port: 3306130 Connect_Retry: 60131 Master_Log_File: mysql-bin.000013132 Read_Master_Log_Pos: 502547133 Relay_Log_File: relay-bin.000013134 Relay_Log_Pos: 251135 Relay_Master_Log_File: mysql-bin.000013136 Slave_IO_Running: Yes #<==IO线程状态必须为Yes137 Slave_SQL_Running: Yes #<==SQL线程状态必须为Yes138 Replicate_Do_DB: 139 Replicate_Ignore_DB: mysql140 Replicate_Do_Table: 141 Replicate_Ignore_Table: 142 Replicate_Wild_Do_Table: 143 Replicate_Wild_Ignore_Table: 144 Last_Errno: 0145 Last_Error: 146 Skip_Counter: 0147 Exec_Master_Log_Pos: 502547148 Relay_Log_Space: 502986149 Until_Condition: None150 Until_Log_File: 151 Until_Log_Pos: 0152 Master_SSL_Allowed: No153 Master_SSL_CA_File: 154 Master_SSL_CA_Path: 155 Master_SSL_Cert: 156 Master_SSL_Cipher: 157 Master_SSL_Key: 158 Seconds_Behind_Master: 0 #<==和主库比同步延迟的秒数,这个参数很重要。159Master_SSL_Verify_Server_Cert: No160 Last_IO_Errno: 0161 Last_IO_Error: 162 Last_SQL_Errno: 0163 Last_SQL_Error:164解题思路:1651)判断主从复制是否异常,主要就是检测如下参数对应的值是否和如下一致。166 Slave_IO_Running: Yes #<==IO线程状态必须为Yes。167 Slave_SQL_Running: Yes #<==SQL线程状态必须为Yes。168 Seconds_Behind_Master: 0 #<==和主库比同步延迟的秒数,这个参数很重要。1692)读取状态数据或状态文件,然后取出对应值,和正确时的值进行比对,如果不符合就表示故障了,即调用报警脚本报警。1703)为了更专业,还可以在当主从不同步时,查看相应错误号,判断对应错误号以进行自动恢复主从复制故障(这些错误号也可以通过配置文件里配置参数实现自动忽略故障)。171以下为参考答案。172首先给出模拟数据(注意,使用时要去掉中文注释)。173[root@oldboy scripts]# cat slave.log174*************************** 1. row ***************************175 Slave_IO_State: Waiting for master to send event176 Master_Host: 10.0.0.51 177 Master_User: rep178 Master_Port: 3306179 Connect_Retry: 60180 Master_Log_File: mysql-bin.000013181 Read_Master_Log_Pos: 502547182 Relay_Log_File: relay-bin.000013183 Relay_Log_Pos: 251184 Relay_Master_Log_File: mysql-bin.000013185 Slave_IO_Running: Yes186 Slave_SQL_Running: Yes187 Replicate_Do_DB: 188 Replicate_Ignore_DB: mysql189 Replicate_Do_Table: 190 Replicate_Ignore_Table: 191 Replicate_Wild_Do_Table: 192 Replicate_Wild_Ignore_Table: 193 Last_Errno: 0194 Last_Error: 195 Skip_Counter: 0196 Exec_Master_Log_Pos: 502547197 Relay_Log_Space: 502986198 Until_Condition: None199 Until_Log_File: 200 Until_Log_Pos: 0201 Master_SSL_Allowed: No202 Master_SSL_CA_File: 203 Master_SSL_CA_Path: 204 Master_SSL_Cert: 205 Master_SSL_Cipher: 206 Master_SSL_Key: 207 Seconds_Behind_Master: 0208Master_SSL_Verify_Server_Cert: No209 Last_IO_Errno: 0210 Last_IO_Error: 211 Last_SQL_Errno: 0212 Last_SQL_Error:213然后开发脚本,开发脚本有多种方法,下面分别给出。214方法1:215scripts]# awk -F ': ' '/_Running|_Behind/{print $NF}' slave.log216#<==获取所有复制相关的状态值。217Yes218Yes2190220[root@oldboy scripts]# cat 13_6_1.sh221count=0222status=($(awk -F ': ' '/_Running|_Behind/{print $NF}' slave.log)) #<==获取所有复制相关的状态值赋值给数组status。223for((i=0;i<${#status[*]};i++)) #<==循环数组元素。224do225 if [ "${status[${i}]}" != "Yes" -a "${status[${i}]}" != "0" ] #<==如果数组元素值不为Yes并且不为0任意一个,那就表示复制出故障了。226 then227 let count+=1 #<==错误数加1。228 fi229done230if [ $count -ne 0 ];then #<==只要错误数不等于0,就表示状态值肯定有有问题的。231 echo "mysql replcation is failed" #<==提示复制出现问题。232else233 echo "mysql replcation is sucess" #<==否则提示复制正常。234fi235说明:本答案是为了引导读者,没有加每30秒。236测试结果如下:237scripts]# sh 13_6_1.sh 238mysql replcation is sucess239scripts]# sed -i 's#Slave_IO_Running: Yes#Slave_IO_Running: No#g' slave.log #<==提模拟IO线程故障。240scripts]# sh 13_6_1.sh241mysql replcation is failed242方法2:本方法和方法1实现的功能差不多,但是开发手法就更高大上一些。243244CheckDb(){245 count=0246status=($(awk -F ': ' '/_Running|_Behind/{print $NF}' slave.log))247for((i=0;i<${#status[*]};i++))248do249 if [ "${status[${i}]}" != "Yes" -a "${status[${i}]}" != "0" ]250 then251 let count+=1252 fi253done254if [ $count -ne 0 ];then255 echo "mysql replcation is failed"256 return 1257else258 echo "mysql replcation is sucess"259 return 0260fi261}262main(){263while true264do265 CheckDb266 sleep 3267done268}269main270测试结果如下:271scripts]# sed -i 's#Slave_IO_Running: No#Slave_IO_Running: Yes#g' slave.log #<==模拟IO线程恢复正常。272scripts]# sh 13_6_2.sh 273mysql replcation is sucess274mysql replcation is sucess275mysql replcation is sucess276^C277scripts]# sed -i 's#Slave_IO_Running: Yes#Slave_IO_Running: No#g' slave.log #<==提示复制出现问题。278scripts]# sh 13_6_2.sh 279mysql replcation is failed280mysql replcation is failed281^C282说明:本答案还是没有完全满足题意,例如,报警短信和邮件没有开发。283方法3(此为企业生产正式检查脚本):284285###########################################286# this script function is :287# check_mysql_slave_replication_status288# USER YYYY-MM-DD - ACTION289# oldboy 2009-02-16 - Created290############################################291path=/server/scripts #<==定义脚本存放路径,大家注意这个规范。292MAIL_GROUP="[email protected] [email protected]" #<==邮件列表,以空格隔开。293PAGER_GROUP="18600338340 18911718229" #<==手机列表,以空格隔开。294LOG_FILE="/tmp/web_check.log" #<==日志路径。295USER=root #<==数据库用户。296PASSWORD=oldboy123 #<==用户密码。297PORT=3307 #<==端口。298MYSQLCMD="mysql -u$USER -p$PASSWORD -S /data/$PORT/mysql.sock" #<==登录数据库命令。299error=(1008 1007 1062) #<==可以忽略的主从复制错误号。300RETVAL=0301[ ! -d "$path" ] && mkdir -p $path302function JudgeError(){ #<==定义判断主从复制错误的函数。303 for((i=0;i<${#error[*]};i++))304 do305 if [ "$1" == "${error[$i]}" ] #<==如果传入的错误号和数组里的元素匹配,则执行then后命令。306 then307 echo "MySQL slave errorno is $1,auto repairing it."308 $MYSQLCMD -e "stop slave;set global sql_slave_skip_counter=1;start slave;" #<==自动修复。309 fi310 done311 return $1312}313function CheckDb(){ #<==定义检查数据库主从复制状态的函数。314status=($(awk -F ': ' '/_Running|Last_Errno|_Behind/{print $NF}' slave.log))315 expr ${status[3]} + 1 &>/dev/null #<==这个是延迟状态值,进行是否为数字判断。316 if [ $? -ne 0 ];then #<==如果不为数字。317 status[3]=300 #<==赋值300,当数据库出现复制故障时,延迟这个状态值有可能是NULL,即非数字。318 fi319 if [ "${status[0]}" == "Yes" -a "${status[1]}" == "Yes" -a ${status[3]} -lt 120 ]320 #<==两个线程都为Yes,并且延迟小于120秒,即认为复制状态是正常的。321 then322 #echo "Mysql slave status is ok"323 return 0 #<==返回0。324 else325 #echo "mysql replcation is failed"326 JudgeError ${status[2]} #<==否则将错误号${status[2]},传入JudgeError函数,判断错误号是否可以自动修复。327 fi328}329function MAIL(){ #<==定义邮件函数,在范例11_13讲过此函数。330local SUBJECT_CONTENT=$1 #<==函数的第一个传参赋值给主题变量。331for MAIL_USER in `echo $MAIL_GROUP` #<==遍历邮件列表。332do333 mail -s "$SUBJECT_CONTENT " $MAIL_USER <$LOG_FILE #<==发邮件。334done335}336function PAGER(){#<==定义手机函数,在范例11_13讲过此函数。337 for PAGER_USER in `echo $PAGER_GROUP` #<==遍历手机列表。338 do339 TITLE=$1 #<==函数的第一个传参赋值给主题变量。340 CONTACT=$PAGER_USER #<==手机号赋值给CONTACT变量。341 HTTPGW=http://oldboy.sms.cn/smsproxy/sendsms.action #<==发短信地址,这个地址需要用户付费购买的,如果免费的就得用139,微信替代了。342 #send_message method1343 curl -d cdkey=5ADF-EFA -d password=OLDBOY -d phone=$CONTACT -d message="$TITLE[$2]" $HTTPGW344#<==发送短信报警的命令。cdkey是购买短信网关时,售卖者给的,password是密码,也是售卖者给的。345 done346}347function SendMsg(){348 if [ $1 -ne 0 ] #<==传入$1,如果不为0表示复制有问题,这里的$1即CheckDb里的返回值(用检测失败的次数作为返回值),在后文主函数main执行时调用SendMsg传参时传进来。349 then 350 RETVAL=1351 NOW_TIME=`date +"%Y-%m-%d %H:%M:%S"`#<==报警时间。352 SUBJECT_CONTENT="mysql slave is error,errorno is $2,${NOW_TIME}."#<==报警主题。353 echo -e "$SUBJECT_CONTENT"|tee $LOG_FILE #<==输出信息,并记录到日志。354 MAIL $SUBJECT_CONTENT #<==发邮件报警,$SUBJECT_CONTENT作为函数参数传给MAIL函数体的$1。355 PAGER $SUBJECT_CONTENT $NOW_TIME #<==发短信报警,$SUBJECT_CONTENT作为函数参数传给MAIL函数体的$1,$NOW_TIME作为函数体传给$2。356 else357 echo "Mysql slave status is ok"358 RETVAL=0 #<==以0作为返回值。359 fi360 return $RETVAL361}362function main(){363while true364do365 CheckDb366 SendMsg $? #<==传入第一个参数$?,即CheckDb里的返回值(用检测失败的次数作为返回值)。367 sleep 300368done369}370main371
372
373下面列举的知识点是老男孩要求所有学生必会的,这些脚本知识点中的很多内容不仅仅涉及脚本知识,还有系统命令、大量网络服务的知识,这些都需要读者了解和掌握,Shell编程仅仅是其中的一部分内容。374作为一个合格运维人员,需要掌握的脚本列表如下:3751)系统及各类服务的监控脚本,例如:文件、内存、磁盘、端口,URL监控报警等。3762)监控网站目录下文件是否被篡改,以及站点目录批量被篡改后如何批量恢复的脚本。3773)各类服务Rsync、Nginx、MySQL等的启动及停止专业脚本(使用chkconfig管理)。3784)MySQL主从复制监控报警以及自动处理不复制故障的脚本。3795)一键配置MySQL多实例、一键配置MySQL主从部署脚本。3806)监控HTTP/MySQL/Rsync/NFS/Memcached等服务是否异常的生产脚本。3817)一键软件安装及优化的脚本,比如LANMP、Linux一键优化,一键数据库安装、优化等。3828)MySQL多实例启动脚本,分库、分表自动备份脚本。3839)根据网络连接数以及根据Web日志PV封IP的脚本。38410)监控网站的PV以及流量,并且对流量信息进行统计的脚本。38511)检查Web服务器多个URL地址是否异常的脚本,要可以批量处理且通用。38612)系统的基础优化一键优化的脚本。38713)TCP连接状态及IP统计报警脚本。38814)批量创建用户并设置随机8位密码的脚本。389
390注:到此shell编程重要知识完,重在思路和多练习多实践并且熟悉Linux上的常用命令。391
xxxxxxxxxx281批量生成随机字符文件名2成随机数的 7 种方法: 31)echo $RANDOM 范围是 0-3276742)openssl rand -base64 100 53)date +%s%N64)head /dev/urandom|cksum 75)uuidgen86)cat /proc/sys/kernel/random/uuid 97)mkpasswd(yum install expect -y)10mkpasswd -l 20 -d 10 -C 5 -c 3 -s 211-l 长度12-d 数字13-c 小写字母14-C 大写字母15-s 特殊字符16
17echo "OLDBOY$RANDOM"|md5sum|tr "0-9" "m-z"|cut -c 2-1118cat exam1.sh 1920path=/data/testing21[ -d $path ]||mkdir -p $path22for n in {1..10}23do24 random=`echo "MEI$RANDOM"|md5sum|tr "0-9" "m-z"|cut -c 2-11`25 touch $path/${random}_mei.txt26done27
28
xxxxxxxxxx231批量改名2将exam1中创建的文件中,文件名中mei字串改为test并将扩展名换为大写。3先改一个:4[root@foundation testing]# file=bdscsamccb_mei.txt5[root@foundation testing]# echo ${file/mei.txt/test.TXT}6bdscsamccb_test.TXT7[root@foundation testing]# mv $file `echo ${file/mei.txt/test.TXT}`8[root@foundation testing]# ls `echo ${file/mei.txt/test.TXT}` -l9-rw-r--r--. 1 root root 0 Feb 4 15:50 bdscsamccb_test.TXT10
11for循环1213dir=/data/testing14for file in `ls $dir`;do15 mv ${dir}/${file} `echo ${dir}\/${file/mei.txt/test.TXT}`16done17
18拼接19[root@foundation testing]# ls *.TXT|awk -F "test.TXT" '{print "mv",$0,$1"mei.txt"}'|bash20rename命令21[root@foundation testing]# rename "mei.txt" "test.HTML" *.txt22
23
xxxxxxxxxx681批量创建特殊要求的用户2用户mei01-mei10,并设置随机密码3生成01-104echo {01..10}5seq -w 106
7生成随机密码8openssl rand -base64 1009
10为用户设置密码11echo "password" |passwd --stdin username12chpasswd设置密码13文件要满足下面格式14username:passwd15username:passwd16
17使用循环18exam]# cat exam3_1.sh1920for n in {1..10};do21 pass=`openssl rand -base64 10`22 useradd mei$n23 echo $pass|passwd --stdin mei$n24 echo -e "mei$n\t$passwd" >>./exam3_1.codebook25done26
27exam]# cat exam3_2.sh2829for n in `seq -w 11 15`;do30 pass=`openssl rand -base64 10`31 useradd mei$n32 echo "mei$n:$pass" >>./exam3_2.codebook33done34chpasswd < ./exam3_2.codebool35
36exam]# cat exam3_3.sh3738. /etc/init.d/functions39if [ $UID -ne 0 ];then4041. /etc/init.d/functions42if [ $UID -ne 0 ];then43 echo -e "Permission denied\nneed account root exec the $0"44 exit 145fi46
47for n in {16..20};do48 pass=`openssl rand -base64 10`49 if [ `grep -w "mei$n" /etc/passwd |wc -l` -eq 0 ];then50 useradd mei$n & >/dev/null &&\51 echo $pass|passwd --stdin mei$n &>/dev/null &&\52 echo -e "mei$n\t$pass" >>./exam3_3.codebook &&\53 action "create mei$n user seccessful." /bin/true54 else55 action "create mei$n user false." /bin/false56 fi57done58注意:如果使用循环,那么可以使用命令拼接的方式拼接出整个创建用户和设置密码的过程。59
60echo stu{01..10}|tr " " "\n"|sed -r 's#(.*)#useradd \1 ; pass=$((RANDOM+10000000)); echo "$pass"|passwd --stdin \1; echo -e "\1 \t `echo "$pass"`">>/tmp/oldboy.log#g'|bash61
62echo stu{11..12}|xargs -n1 useradd ;echo stu{11..12}:`cat /dev/urandom|tr -dc 0-9|fold -w8|head -1`|xargs -n1|tee -a pass.txt|chpasswd63
64echo stu{21..30} | tr ' ' '\n' | sed -e 's/^/useradd /' -e 's/\(stu[0-9]\{2\}\)$/\1 \&\& echo "\1:`echo $[$RANDOM**3] | cut -c1-8`" | tee -a userInfo.txt | cut -d: -f2 | passwd --stdin \1/'|bash65
66echo stu{01..10} |tr ' ' '\n'|sed -rn 's@^(.*)$@useradd \1 ; echo $RANDOM|md5sum|cut -c 1-8 >/data/\1;cat /data/\1|passwd --stdin \1@gp'|bash67
68
xxxxxxxxxx181扫描网络中存活的主机2ping -c 2 -i 1 -w 3 172.25.0.553arping 172.25.0.554nmap -sP 172.25.0.0/245
67network="172.25.0."8for n in {1..254};do9 {10 if `ping -c 1 -w 3 ${network}${n}` &>/dev/null11 then12 echo -e "${network}${n} is \e[40;32;1mup\e[0m"13 else14 echo -e "${network}${n} is \e[40;33;1mdown\e[0m"15 fi16 } &17done18
xxxxxxxxxx2991解决DOS攻击2写一个Shell脚本解决DOS攻击生产案例。3请根据web日志或者或者网络连接数,监控当某个IP并发连接数或者短时内PV达到100(读者根据实际情况设定),即调用防火墙命令封掉对应的IP。4
5封IP:iptables -I INPUT -s IP地址-j DROP。6web日志或网络连接数:日志文件,netstat -an|grep -i EST>netstat.log,排序去重。7判断pv或者链接数大于100,取出Ip让后封。8netstat.log日志内容模拟9Active Internet connections (servers and established)10Proto Recv-Q Send-Q Local Address Foreign Address State 11tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 12tcp 0 0 115.29.49.213:80 117.136.27.254:13779 SYN_RECV 13tcp 0 0 115.29.49.213:80 113.97.117.157:1847 SYN_RECV 14tcp 0 0 115.29.49.213:80 113.97.117.157:1847 SYN_RECV 15tcp 0 0 115.29.49.213:80 113.97.117.157:1847 SYN_RECV 16tcp 0 0 115.29.49.213:80 113.97.117.157:1847 SYN_RECV 17tcp 0 0 115.29.49.213:80 113.97.117.157:1847 SYN_RECV 18tcp 0 0 115.29.49.213:80 113.97.117.157:1847 SYN_RECV 19tcp 0 0 115.29.49.213:80 113.97.117.157:1847 SYN_RECV 20tcp 0 0 115.29.49.213:80 113.97.117.157:1847 SYN_RECV 21tcp 0 0 115.29.49.213:80 113.97.117.157:1847 SYN_RECV 22tcp 0 0 115.29.49.213:80 113.97.117.157:1847 SYN_RECV 23tcp 0 0 115.29.49.213:80 113.97.117.157:1847 SYN_RECV 24tcp 0 0 115.29.49.213:80 113.97.117.157:1847 SYN_RECV 25tcp 0 0 115.29.49.213:80 113.97.117.157:1847 SYN_RECV 26tcp 0 0 115.29.49.213:80 113.97.117.157:1847 SYN_RECV 27tcp 0 0 115.29.49.213:80 113.97.117.157:1847 SYN_RECV 28tcp 0 0 115.29.49.213:80 113.97.117.157:1847 SYN_RECV 29tcp 0 0 115.29.49.213:80 113.97.117.157:1847 SYN_RECV 30tcp 0 0 115.29.49.213:80 113.97.117.157:1847 SYN_RECV 31tcp 0 0 115.29.49.213:80 113.97.117.157:1847 SYN_RECV 32tcp 0 0 115.29.49.213:80 113.97.117.157:1847 SYN_RECV 33tcp 0 0 115.29.49.213:80 113.97.117.157:1847 SYN_RECV 34tcp 0 0 115.29.49.213:80 113.97.117.157:1847 SYN_RECV 35tcp 0 0 115.29.49.213:80 113.97.117.157:1847 SYN_RECV 36tcp 0 0 115.29.49.213:80 113.97.117.157:1847 SYN_RECV 37tcp 0 0 115.29.49.213:80 113.97.117.157:1847 SYN_RECV 38tcp 0 0 115.29.49.213:80 113.97.117.157:1847 SYN_RECV 39tcp 0 0 115.29.49.213:80 113.97.117.157:1847 SYN_RECV 40tcp 0 0 115.29.49.213:80 117.136.40.20:19594 SYN_RECV 41tcp 0 0 115.29.49.213:80 117.136.40.20:19595 SYN_RECV 42tcp 0 0 115.29.49.213:80 121.236.219.69:45363 SYN_RECV 43tcp 0 0 0.0.0.0:21 0.0.0.0:* LISTEN 44tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN 45tcp 0 0 0.0.0.0:3306 0.0.0.0:* LISTEN 46tcp 0 0 115.29.49.213:80 123.163.178.32:3009 ESTABLISHED 47tcp 0 0 115.29.49.213:80 123.163.178.32:3009 ESTABLISHED 48tcp 0 0 115.29.49.213:80 123.163.178.32:3009 ESTABLISHED 49tcp 0 0 115.29.49.213:80 123.163.178.32:3009 ESTABLISHED 50tcp 0 0 115.29.49.213:80 123.163.178.32:3009 ESTABLISHED 51tcp 0 0 115.29.49.213:80 123.163.178.32:3009 ESTABLISHED 52tcp 0 0 115.29.49.213:80 123.163.178.32:3009 ESTABLISHED 53tcp 0 0 115.29.49.213:80 123.163.178.32:3009 ESTABLISHED 54tcp 0 0 115.29.49.213:80 123.163.178.32:3009 ESTABLISHED 55tcp 0 0 115.29.49.213:80 123.163.178.32:3009 ESTABLISHED 56tcp 0 0 115.29.49.213:80 123.163.178.32:3009 ESTABLISHED 57tcp 0 0 115.29.49.213:80 123.163.178.32:3009 ESTABLISHED 58tcp 0 0 115.29.49.213:80 123.163.178.32:3009 ESTABLISHED 59tcp 0 0 115.29.49.213:80 123.163.178.32:3009 ESTABLISHED 60tcp 0 0 115.29.49.213:80 123.163.178.32:3009 ESTABLISHED 61tcp 0 0 115.29.49.213:80 123.163.178.32:3009 ESTABLISHED 62tcp 0 0 115.29.49.213:80 123.163.178.32:3009 ESTABLISHED 63tcp 0 0 115.29.49.213:80 123.163.178.32:3009 ESTABLISHED 64tcp 0 0 115.29.49.213:80 123.163.178.32:3009 ESTABLISHED 65tcp 0 0 115.29.49.213:80 123.163.178.32:3009 ESTABLISHED 66tcp 0 0 115.29.49.213:80 123.163.178.32:3009 ESTABLISHED 67tcp 0 0 115.29.49.213:80 123.163.178.32:3009 ESTABLISHED 68tcp 0 0 115.29.49.213:80 123.163.178.32:3009 ESTABLISHED 69tcp 0 0 115.29.49.213:80 123.163.178.32:3009 ESTABLISHED 70tcp 0 0 115.29.49.213:80 123.163.178.32:3009 ESTABLISHED 71tcp 0 0 115.29.49.213:80 117.136.1.202:21158 TIME_WAIT 72tcp 0 0 115.29.49.213:80 220.191.224.154:48550 ESTABLISHED 73tcp 0 0 115.29.49.213:80 183.32.61.109:5600 ESTABLISHED 74tcp 0 0 115.29.49.213:80 183.32.61.109:5600 ESTABLISHED 75tcp 0 0 115.29.49.213:80 183.32.61.109:5600 ESTABLISHED 76tcp 0 0 115.29.49.213:80 183.32.61.109:5600 ESTABLISHED 77tcp 0 0 115.29.49.213:80 183.32.61.109:5600 ESTABLISHED 78tcp 0 0 115.29.49.213:80 183.32.61.109:5600 ESTABLISHED 79tcp 0 0 115.29.49.213:80 183.32.61.109:5600 ESTABLISHED 80tcp 0 0 115.29.49.213:80 183.32.61.109:5600 ESTABLISHED 81tcp 0 0 115.29.49.213:80 183.32.61.109:5600 ESTABLISHED 82tcp 0 0 115.29.49.213:80 183.32.61.109:5600 ESTABLISHED 83tcp 0 0 115.29.49.213:80 183.32.61.109:5600 ESTABLISHED 84tcp 0 0 115.29.49.213:80 183.32.61.109:5600 ESTABLISHED 85tcp 0 0 115.29.49.213:80 183.32.61.109:5600 ESTABLISHED 86tcp 0 0 115.29.49.213:80 183.32.61.109:5600 ESTABLISHED 87tcp 0 0 115.29.49.213:80 183.32.61.109:5600 ESTABLISHED 88tcp 0 0 115.29.49.213:80 183.32.61.109:5600 ESTABLISHED 89tcp 0 0 115.29.49.213:80 183.32.61.109:5600 ESTABLISHED 90tcp 0 0 115.29.49.213:80 183.32.61.109:5600 ESTABLISHED 91tcp 0 0 115.29.49.213:80 183.32.61.109:5600 ESTABLISHED 92tcp 0 0 115.29.49.213:80 183.32.61.109:5600 ESTABLISHED 93tcp 0 0 115.29.49.213:80 183.32.61.109:5600 ESTABLISHED 94tcp 0 0 115.29.49.213:80 183.32.61.109:5600 ESTABLISHED 95tcp 0 0 115.29.49.213:80 183.32.61.109:5600 ESTABLISHED 96tcp 0 0 115.29.49.213:80 183.32.61.109:5600 ESTABLISHED 97tcp 0 0 115.29.49.213:80 183.32.61.109:5600 ESTABLISHED 98tcp 0 0 115.29.49.213:80 183.32.61.109:5600 ESTABLISHED 99tcp 0 0 115.29.49.213:80 183.32.61.109:5600 ESTABLISHED 100tcp 0 0 115.29.49.213:80 183.32.61.109:5600 ESTABLISHED 101tcp 0 0 115.29.49.213:80 183.32.61.109:5600 ESTABLISHED 102tcp 0 0 115.29.49.213:80 27.17.23.22:51256 FIN_WAIT2 103tcp 0 0 115.29.49.213:80 218.242.161.183:50519 FIN_WAIT2 104tcp 0 0 115.29.49.213:80 223.104.12.101:49900 TIME_WAIT 105tcp 0 0 115.29.49.213:80 140.206.64.90:62291 TIME_WAIT 106tcp 0 0 115.29.49.213:80 120.237.97.10:54195 ESTABLISHED 107tcp 0 0 115.29.49.213:80 49.80.146.230:13453 FIN_WAIT2 108tcp 0 0 115.29.49.213:80 117.136.1.202:21158 TIME_WAIT 109tcp 0 0 115.29.49.213:80 220.191.224.154:48550 ESTABLISHED 110tcp 0 0 115.29.49.213:80 183.32.61.109:5600 ESTABLISHED 111tcp 0 0 115.29.49.213:80 27.17.23.22:51256 FIN_WAIT2 112tcp 0 0 115.29.49.213:80 218.242.161.183:50519 FIN_WAIT2 113tcp 0 0 115.29.49.213:80 223.104.12.101:49900 TIME_WAIT 114tcp 0 0 115.29.49.213:80 140.206.64.90:62291 TIME_WAIT 115tcp 0 0 115.29.49.213:80 120.237.97.10:54195 ESTABLISHED 116tcp 0 0 115.29.49.213:80 49.80.146.230:13453 FIN_WAIT2 117tcp 0 0 115.29.49.213:80 117.136.1.202:21158 TIME_WAIT 118tcp 0 0 115.29.49.213:80 220.191.224.154:48550 ESTABLISHED 119tcp 0 0 115.29.49.213:80 183.32.61.109:5600 ESTABLISHED 120tcp 0 0 115.29.49.213:80 27.17.23.22:51256 FIN_WAIT2 121tcp 0 0 115.29.49.213:80 218.242.161.183:50519 FIN_WAIT2 122tcp 0 0 115.29.49.213:80 223.104.12.101:49900 TIME_WAIT 123tcp 0 0 115.29.49.213:80 140.206.64.90:62291 TIME_WAIT 124tcp 0 0 115.29.49.213:80 120.237.97.10:54195 ESTABLISHED 125tcp 0 0 115.29.49.213:80 49.80.146.230:13453 FIN_WAIT2 126tcp 0 0 115.29.49.213:80 117.136.1.202:21158 TIME_WAIT 127tcp 0 0 115.29.49.213:80 220.191.224.154:48550 ESTABLISHED 128tcp 0 0 115.29.49.213:80 183.32.61.109:5600 ESTABLISHED 129tcp 0 0 115.29.49.213:80 27.17.23.22:51256 FIN_WAIT2 130tcp 0 0 115.29.49.213:80 218.242.161.183:50519 FIN_WAIT2 131tcp 0 0 115.29.49.213:80 223.104.12.101:49900 TIME_WAIT 132tcp 0 0 115.29.49.213:80 140.206.64.90:62291 TIME_WAIT 133tcp 0 0 115.29.49.213:80 120.237.97.10:54195 ESTABLISHED 134tcp 0 0 115.29.49.213:80 49.80.146.230:13453 FIN_WAIT2 135tcp 0 0 115.29.49.213:80 117.136.1.202:21158 TIME_WAIT 136tcp 0 0 115.29.49.213:80 220.191.224.154:48550 ESTABLISHED 137tcp 0 0 115.29.49.213:80 183.32.61.109:5600 ESTABLISHED 138tcp 0 0 115.29.49.213:80 27.17.23.22:51256 FIN_WAIT2 139tcp 0 0 115.29.49.213:80 218.242.161.183:50519 FIN_WAIT2 140tcp 0 0 115.29.49.213:80 223.104.12.101:49900 TIME_WAIT 141tcp 0 0 115.29.49.213:80 140.206.64.90:62291 TIME_WAIT 142tcp 0 0 115.29.49.213:80 120.237.97.10:54195 ESTABLISHED 143tcp 0 0 115.29.49.213:80 49.80.146.230:13453 FIN_WAIT2 144tcp 0 0 115.29.49.213:80 117.136.1.202:21158 TIME_WAIT 145tcp 0 0 115.29.49.213:80 220.191.224.154:48550 ESTABLISHED 146tcp 0 0 115.29.49.213:80 183.32.61.109:5600 ESTABLISHED 147tcp 0 0 115.29.49.213:80 27.17.23.22:51256 FIN_WAIT2 148tcp 0 0 115.29.49.213:80 218.242.161.183:50519 FIN_WAIT2 149tcp 0 0 115.29.49.213:80 223.104.12.101:49900 TIME_WAIT 150tcp 0 0 115.29.49.213:80 140.206.64.90:62291 TIME_WAIT 151tcp 0 0 115.29.49.213:80 120.237.97.10:54195 ESTABLISHED 152tcp 0 0 115.29.49.213:80 49.80.146.230:13453 FIN_WAIT2 153tcp 0 0 115.29.49.213:80 117.136.1.202:21158 TIME_WAIT 154tcp 0 0 115.29.49.213:80 220.191.224.154:48550 ESTABLISHED 155tcp 0 0 115.29.49.213:80 183.32.61.109:5600 ESTABLISHED 156tcp 0 0 115.29.49.213:80 27.17.23.22:51256 FIN_WAIT2 157tcp 0 0 115.29.49.213:80 218.242.161.183:50519 FIN_WAIT2 158tcp 0 0 115.29.49.213:80 223.104.12.101:49900 TIME_WAIT 159tcp 0 0 115.29.49.213:80 140.206.64.90:62291 TIME_WAIT 160tcp 0 0 115.29.49.213:80 120.237.97.10:54195 ESTABLISHED 161tcp 0 0 115.29.49.213:80 49.80.146.230:13453 FIN_WAIT2 162tcp 0 0 115.29.49.213:80 117.136.1.202:21158 TIME_WAIT 163tcp 0 0 115.29.49.213:80 220.191.224.154:48550 ESTABLISHED 164tcp 0 0 115.29.49.213:80 183.32.61.109:5600 ESTABLISHED 165tcp 0 0 115.29.49.213:80 27.17.23.22:51256 FIN_WAIT2 166tcp 0 0 115.29.49.213:80 218.242.161.183:50519 FIN_WAIT2 167tcp 0 0 115.29.49.213:80 223.104.12.101:49900 TIME_WAIT 168tcp 0 0 115.29.49.213:80 140.206.64.90:62291 TIME_WAIT 169tcp 0 0 115.29.49.213:80 120.237.97.10:54195 ESTABLISHED 170tcp 0 0 115.29.49.213:80 49.80.146.230:13453 FIN_WAIT2 171tcp 0 0 115.29.49.213:80 117.136.1.202:21158 TIME_WAIT 172tcp 0 0 115.29.49.213:80 220.191.224.154:48550 ESTABLISHED 173tcp 0 0 115.29.49.213:80 183.32.61.109:5600 ESTABLISHED 174tcp 0 0 115.29.49.213:80 27.17.23.22:51256 FIN_WAIT2 175tcp 0 0 115.29.49.213:80 218.242.161.183:50519 FIN_WAIT2 176tcp 0 0 115.29.49.213:80 223.104.12.101:49900 TIME_WAIT 177tcp 0 0 115.29.49.213:80 140.206.64.90:62291 TIME_WAIT 178tcp 0 0 115.29.49.213:80 120.237.97.10:54195 ESTABLISHED 179tcp 0 0 115.29.49.213:80 49.80.146.230:13453 FIN_WAIT2 180tcp 0 0 115.29.49.213:80 117.136.1.202:21158 TIME_WAIT 181tcp 0 0 115.29.49.213:80 220.191.224.154:48550 ESTABLISHED 182tcp 0 0 115.29.49.213:80 183.32.61.109:5600 ESTABLISHED 183tcp 0 0 115.29.49.213:80 27.17.23.22:51256 FIN_WAIT2 184tcp 0 0 115.29.49.213:80 218.242.161.183:50519 FIN_WAIT2 185tcp 0 0 115.29.49.213:80 223.104.12.101:49900 TIME_WAIT 186tcp 0 0 115.29.49.213:80 140.206.64.90:62291 TIME_WAIT 187tcp 0 0 115.29.49.213:80 120.237.97.10:54195 ESTABLISHED 188tcp 0 0 115.29.49.213:80 49.80.146.230:13453 FIN_WAIT2 189tcp 0 0 115.29.49.213:80 113.104.25.50:56714 FIN_WAIT2 190tcp 0 0 115.29.49.213:80 101.226.89.193:41639 ESTABLISHED 191tcp 0 0 115.29.49.213:80 119.147.225.185:58321 TIME_WAIT 192tcp 0 0 115.29.49.213:80 54.183.177.237:64129 TIME_WAIT 193tcp 0 0 115.29.49.213:80 120.198.202.48:41960 ESTABLISHED 194tcp 0 1 115.29.49.213:80 119.127.188.242:38843 FIN_WAIT1 195tcp 0 0 115.29.49.213:34081 223.4.9.70:80 TIME_WAIT 196tcp 0 0 115.29.49.213:80 58.223.4.14:46716 FIN_WAIT2 197tcp 0 0 115.29.49.213:80 122.90.74.255:12177 FIN_WAIT2 198tcp 0 0 115.29.49.213:80 59.53.166.165:62253 ESTABLISHED 199tcp 0 0 115.29.49.213:80 219.133.40.13:34113 ESTABLISHED 200tcp 0 0 115.29.49.213:80 222.175.140.230:29902 TIME_WAIT 201tcp 0 0 115.29.49.213:80 54.77.101.105:49967 TIME_WAIT 202tcp 0 0 115.29.49.213:80 54.207.37.100:63364 TIME_WAIT 203tcp 0 0 115.29.49.213:80 125.118.62.149:61840 FIN_WAIT2 204tcp 0 0 115.29.49.213:80 112.117.173.124:50367 ESTABLISHED 205tcp 0 0 115.29.49.213:80 120.194.52.156:2752 FIN_WAIT2 206tcp 0 0 115.29.49.213:80 114.106.68.5:54231 ESTABLISHED 207tcp 0 0 115.29.49.213:80 27.154.82.136:3013 FIN_WAIT2 208tcp 0 0 115.29.49.213:80 182.245.82.46:55306 FIN_WAIT2 209tcp 0 0 115.29.49.213:80 117.92.15.157:29926 TIME_WAIT 210tcp 0 0 115.29.49.213:80 163.179.63.118:62371 ESTABLISHED 211tcp 0 777 115.29.49.213:80 106.59.15.116:1673 ESTABLISHED 212tcp 0 777 115.29.49.213:80 117.22.215.8:1382 ESTABLISHED 213tcp 0 0 115.29.49.213:80 114.217.182.123:51960 TIME_WAIT 214tcp 0 0 115.29.49.213:80 118.242.18.177:24615 ESTABLISHED 215tcp 0 0 115.29.49.213:80 220.191.224.154:23380 TIME_WAIT 216tcp 0 0 115.29.49.213:80 119.78.240.118:59230 FIN_WAIT2 217tcp 0 0 115.29.49.213:80 218.83.11.138:52739 TIME_WAIT 218tcp 0 0 115.29.49.213:80 122.70.113.17:57809 TIME_WAIT 219tcp 0 0 115.29.49.213:80 121.235.160.76:2487 TIME_WAIT 220tcp 0 0 115.29.49.213:80 111.175.68.97:49920 TIME_WAIT 221tcp 0 1 115.29.49.213:80 221.137.78.206:54593 FIN_WAIT1 222tcp 0 0 115.29.49.213:80 119.121.180.245:14524 TIME_WAIT 223tcp 0 0 115.29.49.213:80 123.151.42.52:55816 ESTABLISHED 224tcp 0 0 115.29.49.213:80 120.192.146.19:26133 FIN_WAIT2 225tcp 0 0 115.29.49.213:80 113.107.56.233:45496 TIME_WAIT 226tcp 0 1 115.29.49.213:80 119.249.255.140:1664 FIN_WAIT1 227tcp 0 0 115.29.49.213:80 222.132.131.91:5451 ESTABLISHED 228tcp 0 0 115.29.49.213:80 183.32.61.109:5712 FIN_WAIT2 229tcp 0 52 115.29.49.213:22 119.2.28.4:13185 ESTABLISHED 230tcp 0 0 115.29.49.213:80 221.179.140.171:48647 TIME_WAIT 231tcp 0 0 115.29.49.213:80 111.161.61.49:60865 ESTABLISHED 232tcp 0 0 115.29.49.213:80 58.247.119.17:64369 TIME_WAIT 233tcp 0 0 115.29.49.213:80 121.35.208.125:50139 FIN_WAIT2 234tcp 0 0 115.29.49.213:80 118.242.18.177:24619 ESTABLISHED 235tcp 0 0 115.29.49.213:80 111.17.45.226:5492 TIME_WAIT 236tcp 0 0 115.29.49.213:80 114.250.252.127:50802 TIME_WAIT 237tcp 0 0 115.29.49.213:80 49.80.146.230:13424 TIME_WAIT 238tcp 0 0 115.29.49.213:80 113.241.77.56:18509 TIME_WAIT 239tcp 0 0 115.29.49.213:80 101.226.61.186:57302 ESTABLISHED 240tcp 0 0 115.29.49.213:80 59.38.233.215:18224 FIN_WAIT2 241tcp 0 0 115.29.49.213:80 222.70.73.234:52968 FIN_WAIT2 242tcp 0 0 115.29.49.213:80 114.100.142.6:3171 TIME_WAIT 243tcp 0 0 115.29.49.213:80 27.18.159.160:50095 TIME_WAIT 244tcp 0 0 115.29.49.213:80 122.64.91.155:35708 ESTABLISHED 245tcp 0 0 115.29.49.213:80 116.90.81.14:52978 TIME_WAIT 246tcp 0 0 115.29.49.213:80 124.227.212.140:38460 ESTABLISHED 247tcp 0 0 115.29.49.213:80 223.242.103.128:3997 TIME_WAIT 248tcp 0 0 115.29.49.213:80 113.116.147.94:50073 ESTABLISHED 249tcp 0 0 115.29.49.213:80 112.117.173.124:50366 TIME_WAIT 250tcp 0 0 115.29.49.213:80 122.227.191.174:4833 FIN_WAIT2 251tcp 0 0 115.29.49.213:80 42.95.73.152:51472 ESTABLISHED 252tcp 0 0 115.29.49.213:80 58.215.136.140:56794 TIME_WAIT 253tcp 0 0 115.29.49.213:80 116.90.81.14:52974 TIME_WAIT 254tcp 0 0 115.29.49.213:80 223.100.156.53:59779 TIME_WAIT 255tcp 0 0 115.29.49.213:80 125.112.122.240:44893 FIN_WAIT2 256tcp 0 0 115.29.49.213:80 14.211.169.36:26342 TIME_WAIT 257tcp 0 0 115.29.49.213:80 114.250.252.127:50809 TIME_WAIT 258tcp 0 0 115.29.49.213:80 14.157.228.55:3184 FIN_WAIT2 259tcp 0 0 115.29.49.213:80 112.113.160.225:3029 TIME_WAIT 260tcp 0 0 115.29.49.213:80 14.17.11.196:33403 ESTABLISHED 261tcp 0 0 115.29.49.213:80 36.249.78.78:2615 FIN_WAIT2 262tcp 0 0 115.29.49.213:80 114.105.192.151:1312 ESTABLISHED 263tcp 0 0 115.29.49.213:80 118.242.18.177:24616 FIN_WAIT2 264tcp 0 0 115.29.49.213:80 27.191.14.232:50272 FIN_WAIT2 265tcp 0 0 115.29.49.213:80 119.187.139.167:1779 FIN_WAIT2 266tcp 0 0 115.29.49.213:80 218.75.147.14:5195 TIME_WAIT 267tcp 0 0 115.29.49.213:80 1.204.201.226:12694 ESTABLISHED268
269270awk '{S[$1]++}END{for(key in S) print S[key],key}' access_2020-1-8.log|sort -rn|head >/tmp/ip.log 271while read line 272do 273ip=`echo $line|awk '{print $2}'` 274count=`echo $line|awk '{print $1}'` 275if [ $count -gt 100 -a `grep "$ip" /tmp/drop.log|wc -l` -lt 1 ] 276then 277iptables -I INPUT -s $ip -j DROP &&\ 278echo "$ip" >>/tmp/drop.log 279else 280echo "$ip" >>/tmp/accept.log 281fi 282done</tmp/ip.log283
284285awk '/ESTAB/{print $0}' netstat.log |awk -F "[ :]+" '{print $(NF-3)}'|sort|uniq -c|sort -rn|head >286/tmp/ip.log287while read line288do289 ip=`echo $line|awk '{print $2}'`290 count=`echo $line|awk '{print $1}'`291 if [ $count -gt 10 -a `grep "$ip" /tmp/drop.log|wc -l` -lt 1 ]292 then293 iptables -I INPUT -s $ip -j DROP &&\294 echo "$ip" >>/tmp/drop.log295 else296 echo "$ip" >>/tmp/accept.log297 fi298done</tmp/ip.log299
xxxxxxxxxx171数据库分库备份脚本2常规备份3mysqldump -B test mei|gzip >bak.sql.gz4分库备份:5mysqldump -B mei|gzip >bak.sql.gz 6mysqldump -B test|gzip >bak.sql.gz7
89path=/backup 10mysql="mysql -uroot -ptest" 11mysqldump="mysqldump -uroot -ptest" 12[ -d $path ]||mkdir $path -p 13for dbname in `$mysql -e "show databases;" 2>/dev/null|grep -v _schema|sed 1d` 14do 15$mysqldump -B $dbname|gzip >$path/${dbname}_$(date +%F).sql.gz 2>/dev/null 16done17
xxxxxxxxxx211mysql数据库分库分表备份2mysqldump mei t1 t2|gzip >bak.sql.gz3mysqldump -B mei |gzip >bak.sql.gz: 4mysqldump mei t1 5mysqldump mei t2 6mysqldump mei t37
89path=/backup 10[ -d $path ]||mkdir $path -p 11for dbname in `mysql -e "show databases;"|grep -v _schema|sed 1d` 12do 13 for tname in `mysql -e "show tables from $dbname;"|sed 1d`14 do15 if [ "$dbname" = "mysql" ];then16 mysqldump --skip-lock-tables $dbname $tname|gzip >$path/${dbname}-${tname}.sql.gz17 else18 mysqldump $dbname $tname|gzip >$path/${dbname}-${tname}.sql.gz19 fi20done21
xxxxxxxxxx1581SSH免交互批量分发脚本(CentOS6)23# mzy 2019-09-22 Add Features4# another: meizy 5# contact QQ:3594629626export PATH=/bin:$PATH7
8# output command help manual9function output_help(){10 echo -e "Usage :\n\n--help|-h\tget command help.\n\te.g:batchsent.sh --help\n\ncommand public key distribution:\n\t\e[40;32;1mbatchsent.sh [ip/hostname]\e[0;0;0m\n\nexample:\n\te.g:batchsent.sh 192.168.0.1\n\tor use default batchsent public key:\n\te.g:batchsent.sh\n\nexplanation:\n\t1.hostname needs to be able to be resolved IP address.\n\t2.Run this script need to have root privileges.\n\t3.The current system needs to be able to use yum install sshpass software."11}12
13# Check whether the IP address or host name of the obvious error14function check_ip_format(){15 ip=$116 echo ${ip} |sed -r 's#([0-9]+).#\1#g' |test -n "`sed -n '/^[0-9][0-9]*$/p'`" >/dev/null 2>&117 if [ $? -eq 0 ];then18 count=`echo ${ip}|sed -r 's#([0-9]+).#\1\n#g'|grep -v '^$' | wc -l`19 if [ ${count} -eq 4 ];then20 return 021 else22 echo -e "\e[40;31;1merror\e[0;0;0m:this host(${ip}) ip---\e[40;31;1mThere are obvious errors\e[0;0;0m"23 output_help24 return 125 fi26 else27 ping -c 3 ${ip} >/dev/null 2>&128 if [ $? -eq 0 ];then29 return 030 else31 echo -e "\e[40;31;1merror\e[0;0;0m:this host(${ip}) name---\e[40;31;1mcan not be resolved\e[0;0;0m"32 output_help 33 return 134 fi35 fi36}37
38# Single IP or host public key distribution39function sent_pub_key(){40 ip=$141 sshpass -prewqrewsdsds ssh "-o StrictHostKeyChecking=no" root@${ip} hostname >/dev/null 2>&142 if [ $? -eq 0 ];then43 echo -e "${ip} \tpublic keys \e[40;34;1malready exist\e[0;0;0m,can be used normally."44 else45 ping -c 3 ${ip} >/dev/null 2>&146 if [ $? -eq 0 ];then47 sshpass -ptemplate ssh-copy-id -i /root/.ssh/id_rsa.pub "-o StrictHostKeyChecking=no root@${ip}" >/dev/null 2>&148 echo -e "${ip} \tpublic keys \e[40;32;1msent successfully\e[0;0;0m,can be used normally."49 else50 echo -e "${ip} \tthis host(${ip}) is \e[40;31;1mnot online\e[0;0;0m"51 fi52 fi53}54
55# define default host56function default_batch_sent_pub_key(){57 for ip_addr in 172.16.0.{31,41,51,71,5,6,7,8,9};do58 sent_pub_key ${ip_addr}59 done60}61
62# default ip or host public key distribution63function batch_sent_pub_key(){64 ip_addr=$165 sent_pub_key ${ip_addr}66}67
68# check the packages needed69function check_sshpass(){70 if [ ! -f /usr/bin/sshpass ];then71 yum install -y sshpass >/dev/null 2>&172 if [ $? -ne 0 ];then73 echo -e "\e[40;31;1merror\e[0;0;0m:install sshpass failed,check to see if the current user has root privileges."74 exit 175 fi76 fi77}78
79# check -h or --help args80function check_help_args(){81 args=$182 case ${args} in83 "--help")84 output_help85 exit 186 ;;87 "-h")88 output_help89 exit 190 ;;91 esac92}93
94# The implementation of public key distribution by check_help_args function95# In this way the code is more complex, not recommended96function exec_batch_sent_by_check_help_args(){97 check_help_args $198 if [ $# -eq 1 ];then99 check_ip_format $1100 if [ $? -eq 0 ];then101 batch_sent_pub_key $1102 fi103 fi104}105
106# The implementation of public key distribution by if statment107# Such code simpler, recommended108function exec_batch_sent_by_if_statment(){109 if [ $# -eq 1 ];then110 if [ $1 == '--help' ] || [ $1 == '-h' ];then111 output_help112 else113 check_ip_format $1114 if [ $? -eq 0 ];then115 batch_sent_pub_key $1116 fi117 fi118 fi119}120
121# Check the generated keys122function check_the_generated_keys(){123 if [ -f /root/.ssh/id_rsa -a -f /root/.ssh/id_rsa.pub ];then124 return 0125 else126 ssh-keygen -t rsa -f /root/.ssh/id_rsa -N ""127 if [ $? -eq 0 ];then128 return 0129 else130 echo -e "\e[40;31;1merror\e[0;0;0m:install sshpass failed,check to see if the current user has root privileges."131 return 1132 fi133 fi134}135
136# main137if [ $# -eq 0 ];then138 check_sshpass139 check_the_generated_keys140 if [ $? -eq 0 ];then141 default_batch_sent_pub_key142 else143 exit 1144 fi145else146 until [ $# -eq 0 ];do147 check_sshpass148 check_the_generated_keys149 if [ $? -eq 0 ];then150 exec_batch_sent_by_if_statment $1151 else152 exit 1153 fi154 shift155 done156fi157
158
xxxxxxxxxx421破解RANDOM随机数2已知下面的字符串是通过RANDOM随机数变量md5sum后,再截取一部分连续字符串的结果,请破解这些字符串对应的使用md5sum处理前的RANDOM对应的数字?321029299400205d1c5a3da167761f6d12dd7890684b8RANDOM范围:0-32767,需要把0-32767都全部用md5加密。9
1011
12array=(13210292991400205d1c15a3da1677161f6d12dd17890684b18)19Funmd5(){20 for n in {0..32767};do21 echo -e "$n\t`echo $n|md5sum`" >>/tmp/md5sum1.log &22 done23}24FunJudge(){ # 速度要相对快些25 char="`echo ${array[*]}|tr " " "|"`"26 egrep "$char" /tmp/md5sum1.log27}28function judge(){29 for n in ${array[*]};do 30 find=`grep $n /tmp/md5sum.log`31 if [ `grep $n $find|wc -l` -eq 1 ];then32 echo $find33 fi34 done35}36main(){37 Funmd538 FunJudge39}40main41
42
xxxxxxxxxx391批量检查多个网站是否正常2要求:31、使用shell数组方法实现,检测策略尽量模拟用户访问。42、每10秒钟做一次所有的检测,无法访问的输出报警。53、待检测的地址如下6www.mei.com7http://10.0.0.78
910. /etc/init.d/functions 11URL=( 12http://www.mei.com 13http://10.0.0.7 14) 15CheckUrl(){ 16 wget -T 5 --spider -o /dev/null -q $1 17 if [ $? -eq 0 ] 18 then 19 action "$1 is successful" /bin/true 20 else 21 action "$1 is failure" /bin/false 22 fi 23} 24DealUrl(){ 25 for url in ${URL[*]} 26 do 27 CheckUrl $url 28 done 29} 30main(){ 31 while true 32 do 33 DealUrl 34 sleep 2 35 echo "---------------------------------------------"36 done 37} 38main39
xxxxxxxxxx391单词字母去重复并排序2用shell 处理以下内容 31、按单词出现频率降序排序!42、按字母出现频率降序排序!5cat test.log6the squid project provides a number of resources to assist users design,implement and support squid installations. Please browse the documentation and support sections for more infomation,by oldboy training.7
8按词出现频率9tr " ," "\n" < test.log | sort | uniq -c | sort -rn10
11tr " ," "\n" < test.log | awk '{S[$1]++}END{for (k in S)print S[k],k}'|sort -rn12
13xargs -n1 < test.log | awk '{S[$1]++}END{for (k in S)print S[k],k}'|sort -rn14
15tr ",." " " <test.log|xargs -n 1|sort|uniq -c|sort -rn|head16
17tr ",." " " <test.log|xargs -n 1|awk '{S[$1]++}END{for(key in S)print S[key],key}'|sort -rn|head18
19awk -F "[,. ]+" '{for(i=1;i<=NF;i++)S[$i]++}END{for(key in S)print S[key],key}' test.log |sort -rn|head20
21awk -F "[ ,.]+" '{for(i=1;i<NF;i++)S[$i]++}END{for(k in S)print S[k],k}' test.log | sort -rn22
23按字母出现频率24grep -o "[^ ]" test.log | sort | uniq -c | sort -rn25
26grep -o "[^ ]" test.log | awk '{S[$1]++}END{for (k in S)print S[k],k}'|sort -rn27
28tr "{ |,|.}" "\n"<test.log|awk -F "" '{for(i=1;i<=NF;i++)array[$i]++}END{for(key in array)print array[key],key|"sort -nr"}'29
30tr "[ ,.]" "\n"<test.log|awk '{for(i=1; i<=length($0); i++) ++S[substr($0,i,1)]} END {for(a in S) print S[a], a|"sort -rn"}'31
32cat test.log|sed 's# ##g'|sed -r 's#(.)#\1\n#g'|sort|uniq -c|sort -rn -k133
34cat test.log|sed 's# ##g'|awk -F "" '{for(n=1;n<=NF;n++) print $n}'|sort|uniq -c|sort -k1 -nr35
36sed 's#[ ,\.]##g' test.log | awk -F "" '{for(i=1;i<NF;i++)S[$i]++}END{for(k in S)print S[k],k}'37
38
39
xxxxxxxxxx321批量管理和文件分发脚本23 台机器A、B、C,实现从A 到B 和C 免秘钥登录,然后开发脚本实现,批量管理远程主机(执行任意命令),批量分发本地任意文件到远端任意路径下。3
4分发脚本:56. /etc/init.d/functions 7if [ $# -ne 2 ] 8 then 9 echo "usage:$0 localdir remotedir" 10 exit 1 11fi 12for n in 8 41 42 43 13do 14 scp -rp $1 172.25.0.$n:$2 &>/dev/null 15 if [ $? -eq 0 ] 16 then 17 action "172.25.0.$n is successful" /bin/true 18 else 19 action "172.25.0.$n is failure" /bin/false 20 fi 21done22查看脚本:2324if [ $# -ne 1 ];then 25 echo "usage:$0 cmd" 26 exit 1 27fi 28for n in 55 30 35;do 29 echo "--------172.25.0.$n---------" 30 ssh 172.25.0.$n $131done32
xxxxxxxxxx1361mysql服务启动停止脚本23# chkconfig: 2345 20 804lockfile=/var/lock/subsys/mysqld5. /etc/init.d/functions6mysqld_pid_file_path="/application/mysql/data/web01.pid"7mysqld_safe=/application/mysql/bin/mysqld_safe8
9start(){10 /bin/sh $mysqld_safe --datadir=/application/mysql/data --pid-file=$mysqld_pid_file_path &>/dev/null &11 retval=$?12 if [ $retval -eq 0 ]13 then14 action "mysql startup ok" /bin/true15 touch $lockfile16 return $retval17 else18 action "mysql startup fail" /bin/false19 return $retval20 fi21}22stop(){23 if test -s "$mysqld_pid_file_path"24 then25 mysqld_pid=`cat $mysqld_pid_file_path`26 if (kill -0 $mysqld_pid &>/dev/null)27 then28 kill $mysqld_pid29 retval=$?30 if [ $retval -eq 0 ]31 then32 action "mysql stop ok" /bin/true33 rm $lockfile34 return $retval35 else36 action "mysql stop fail" /bin/false37 return $retval38 fi39 else40 echo " mysqld process is not exist."41 return 242 fi43 else44 echo "$mysqld_pid_file_path is not exist,or mysqld does not startup."45 fi46}47case "$1" in48 start)49 start50 retval=$?51 ;;52 stop)53 stop54 retval=$?55 ;;56 restart)57 stop58 sleep 259 start60 retval=$?61 ;;62 *)63 echo "usage:$0 {start|stop|restart}"64 exit 165esac66exit $retval67
68改进6970# chkconfig: 2345 20 8071lockfile=/var/lock/subsys/mysqld72. /etc/init.d/functions73mysqld_pid_file_path="/application/mysql/data/web01.pid"74mysqld_safe=/application/mysql/bin/mysqld_safe75
76start(){77 /bin/sh $mysqld_safe --datadir=/application/mysql/data --pid-file=$mysqld_pid_file_path &>/dev/null &78 retval=$?79 sleep 280 if [ $retval -eq 0 ]81 then82 action "mysql startup ok" /bin/true83 touch $lockfile84 return $retval85 else86 action "mysql startup fail" /bin/false87 return $retval88 fi89}90stop(){91 if test -s "$mysqld_pid_file_path"92 then93 mysqld_pid=`cat $mysqld_pid_file_path`94 if (kill -0 $mysqld_pid &>/dev/null)95 then96 kill $mysqld_pid97 retval=$?98 sleep 299 if [ $retval -eq 0 ]100 then101 action "mysql stop ok" /bin/true102 rm $lockfile103 return $retval104 else105 action "mysql stop fail" /bin/false106 return $retval107 fi108 else109 echo " mysqld process is not exist."110 return 2111 fi112 else113 echo "$mysqld_pid_file_path is not exist,or mysqld does not startup."114 fi115}116case "$1" in117 start)118 start119 retval=$?120 ;;121 stop)122 stop123 retval=$?124 ;;125 restart)126 stop127 sleep 2128 start129 retval=$?130 ;;131 *)132 echo "usage:$0 {start|stop|restart}"133 exit 1134esac135exit $retval136
在linux下fd叫做文件描述符,在window下fd叫做句柄,所以这就说明了为什么在官方文档中fileno解释是Return the file descriptor or handle used by the connection.
在内核中每一个打开的文件都需要由3种数据结构来进行维护。
根据文中内容,这三种数据结构分别为:打开文件描述符表、打开文件表、inode节点
1.每个进程对应一张打开文件描述符表,这是进程级数据结构,也就是每一个进程都各自有这样一个数据结构;
2.内核维持一张打开文件表,文件表由多个文件表项组成,这是系统级数据结构,也就是说这样的数据结构是针对于整个内核而言的,每个进程都可共享的;
3.每个打开的文件对应一个i节点(i-node)数据结构(Linux下只有i节点没有v节点),由于这是每一个打开的文件与之对应的,因此这也是一个系统级数据结构,存在于内核中,非进程所独有。
https://www.cnblogs.com/lwyeric/p/13598704.html
xxxxxxxxxx31from multiprocessing import Pipe2rpipe, wpipe = Pipe(duplex=False)3print rpipe.fileno() #这个就得到的是fdxxxxxxxxxx51[root@comptserver ~ ]# ls -al /dev | grep fd2lrwxrwxrwx. 1 root root 13 Aug 31 09:40 fd -> /proc/self/fd3lrwxrwxrwx. 1 root root 15 Aug 31 09:40 stderr -> /proc/self/fd/24lrwxrwxrwx. 1 root root 15 Aug 31 09:40 stdin -> /proc/self/fd/05lrwxrwxrwx. 1 root root 15 Aug 31 09:40 stdout -> /proc/self/fd/1https://www.cnblogs.com/alan666/p/8311890.html
xxxxxxxxxx151[root@comptserver ~ ]# lsof +d /root2COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME3bash 3735 root cwd DIR 253,0 4096 100663425 /root4sftp-serv 3751 root cwd DIR 253,0 4096 100663425 /root5bash 4003 root cwd DIR 253,0 4096 100663425 /root6sftp-serv 4034 root cwd DIR 253,0 4096 100663425 /root7vim 25909 root cwd DIR 253,0 4096 100663425 /root8vim 25909 root 6u REG 253,0 12288 101335674 /root/.docker_config.txt.swp9lsof 26796 root cwd DIR 253,0 4096 100663425 /root10lsof 26797 root cwd DIR 253,0 4096 100663425 /root11
12
13[root@comptserver ~ ]# exec 6>fd6.log14[root@comptserver ~ ]# echo "this is fd6.log" 1>&615
xxxxxxxxxx51[root@comptserver ~ ]# lsof -a -p $$ -d 0,1,22COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME3bash 4003 root 0u CHR 136,1 0t0 4 /dev/pts/14bash 4003 root 1u CHR 136,1 0t0 4 /dev/pts/15bash 4003 root 2u CHR 136,1 0t0 4 /dev/pts/1
xxxxxxxxxx111[root@comptserver ~ ]# exec 1>fd1.log2[root@comptserver ~ ]# lsof -a -p $$ -d 0,1,23# 打开新的连接,然后查看4[root@comptserver ~ ]# cat fd1.log5COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME6bash 4003 root 0u CHR 136,1 0t0 4 /dev/pts/17bash 4003 root 1w REG 253,0 0 101335674 /root/fd1.log8bash 4003 root 2u CHR 136,1 0t0 4 /dev/pts/19
10[root@comptserver ~ ]# exec 1>&- # 关闭文件描述符11
bash shell的内建命令exec将并不启动新的shell,而是用要被执行命令替换当前的shell进程,并且将老进程的环境清理掉,而且exec命令后的其它命令将不再执行。
因此,如果你在一个shell里面,执行exec ls;那么,当列出了当前目录后,这个shell就自己退出了,因为这个shell进程已被替换为仅仅执行ls命令的一个进程,执行结束自然也就退出了。为了避免这个影响我们的使用,一般将exec命令放到一个shell脚本里面,用主脚本调用这个脚本,调用点处可以用bash a.sh,(a.sh就是存放该命令的脚本),这样会为a.sh建立一个sub shell去执行,当执行到exec后,该子脚本进程就被替换成了相应的exec的命令。source命令或者”.”,不会为脚本新建shell,而只是将脚本包含的命令在当前shell执行。不过,要注意一个例外,当exec命令来对文件描述符操作的时候,就不会替换shell,而且操作完成后,还会继续执行接下来的命令。
exec 3<&0:这个命令就是将操作符3也指向标准输入。总结:exec 命令:常用来替代当前 shell 并重新启动一个 shell,换句话说,并没有启动子 shell。使用这一命令时任何现有环境都将会被清除。exec 在对文件描述符进行操作的时候,也只有在这时,exec 不会覆盖你当前的 shell 环境。
| exec | 描述 |
|---|---|
exec ls | 在shell中执行ls,ls结束后不返回原来的shell中了 |
exec <file | file中的内容作为标准输入(替代STDIN) |
exec >file | 将标准输出写入file(替代STDOUT) |
exec 3<file | 将file读入到文件描述符3中(此时,创建了文件描述符3) |
sort <&3 | 将文件描述符3作为临时输入,用于sort排序 |
exec 4>file | 将写入文件描述符4中的内容写入file中(此时,创建了文件描述符4) |
ls >&4 | ls将不会有显示,直接写入文件描述符4中了,即上面的file中 |
exec 5<&4 | 创建文件描述符4的拷贝文件描述符5 |
exec 3<&- | 关闭文件描述符3 |
&- 关闭标准输出
n&- 表示将 n 号输出关闭
上述所有形式都可以前导一个数字,此时建立的文件描述符由这个数字指定而不是缺省的 0 或 1。如:
2>file 运行一个命令并把错误输出(文件描述符 2)定向到 file。
2>&1 运行一个命令并把它的标准输出和输出合并。(严格的说是通过复制文件描述符 1 来建立文件描述符 2 ,但效果通常是合并了两个流。)
我们对 2>&1详细说明一下 :2>&1 也就是 FD2=FD1 ,这里并不是说FD2 的值 等于FD1的值,因为 > 是改变送出的数据信道,也就是说把 FD2 的 “数据输出通道” 改为 FD1 的 “数据输出通道”。如果仅仅这样,这个改变好像没有什么作用,因为 FD2 的默认输出和 FD1的默认输出本来都是 monitor,一样的!
但是,当 FD1 是其他文件,甚至是其他 FD 时,这个就具有特殊的用途了。请大家务必理解这一点。
如果 stdin, stdout, stderr 进行了重定向或关闭, 但没有保存原来的 FD, 可以将其恢复到 default 状态吗?
1.如果关闭了
stdin,因为会导致退出,那肯定不能恢复。2.如果重定向或关闭 1stdou1t和1stderr1其中之一,可以恢复,因为他们默认均是送往1monitor1(但不知会否有其他影响)。
如恢复重定向或关闭的 stdout:
exec 1>&2,恢复重定向或关闭的stderr:exec 2>&1。3.如果stdout和stderr全部都关闭了,又没有保存原来的FD,可以用:
exec 1>/dev/tty恢复。
管道和重定向的区别
1.管道是把一个程序的输出作为另一个程序的输入。
2.重定向是把输出定向到文件或者标准流。
Linux mktemp命令用于建立暂存文件。 mktemp建立的一个暂存文件,供shell script使用。 mktemp命令专门用来创建临时文件,并且其创建的临时文件是唯一的。shell会根据mktemp命令创建临时文件,但不会使用默认的umask值(管理权限的)。它会将文件的读写权限分配给文件属主,一旦创建了文件,在shell脚本中就拥有了完整的读写权限,其他人不可访问(除了root)
xxxxxxxxxx211参数:2-q 执行时若发生错误,不会显示任何信息。3-u 暂存文件会在mktemp结束前先行删除。4[文件名参数] 文件名参数必须是以"自订名称.XXXXXX"的格式。5默认情况:mktemp会在本地当前目录创建一个临时文件,创建临时文件时只需要创建模板文件,模板可以包含任意的文件名,文件末尾可以根据需要添加n个X。Demo如下:6[root@master ~] # tempfile=$(mktemp test.XXXX)7[root@master ~] # echo $tempfile8test.coCi9[root@master ~] # mktemp test.XXX // 不能少于三个X test.eIB101112-t 选项:-t选项会强制mktemp命令在系统的临时目录中创建临时文件,创建时mktemp命令会返回临时文件的全路径。1314[root@master ~] # mktemp -t test.XXXX15/tmp/test.1OKR16[root@master ~] # mktemp -t test.XXXXX17/tmp/test.jSwmV18[root@master ~] # mktemp -t test.XXXX19/tmp/test.sQTP2021-d 选项:-d选项告诉mktemp命令创建一个临时目录而不是临时文件
创建命名管道
"FIFO"是一种特殊的文件类型,它允许独立的进程通讯. 一个进程打开FIFO文件进行写操作,而另一个进程对之进行读操作, 然后数据便可以如同在shell或者其它地方常见的的匿名管道一样流式执行.
管道是一种通信机制,用于进程间的通信(也可通过socket进行网络通信),表现出来的形式将前面的每一个进程的输出,直接作为下一个进程的输入
管道命令仅能处理stdout,而error则会忽略
FIFO不同于pipe的地方: 1)FIFO可以看作高级的管道。它突破了pipe的限制(只能用于同源进程之间的通信),可以给任意进程之间建立通信连接;
2)FIFO是一个实际存在于磁盘中的文件;而pipe是由进程创建的,依赖于进程的存活期。
因为它本质上是一个文件,所以进程用open函数来打开一个FIFO,并在打开时指定文件操作模式(只读,只写还是读写)。之后用read(write)函数来读(写)FIFO
当一个进程以只写方式打开FIFO文件,另一个进程以只读方式打开同一个FIFO文件,这样就建立了两个进程之间的通信管道。
实际工作时,pipe和FIFO基本相同的。下面是两者相同的性质:
1)当读一个写端已经被关闭的pipe(或者是读一个没有为写打开的进程的FIFO)时,在所有数据都被读取后,read返回0,以指示到达了文件结束处
2)当写一个读端已经被关闭的pipe(或者是写一个没有为读打开的进程的FIFO)时,write返回-1,并将errno设置为EPIPE
3)在写pipe或者FIFO时,常量PIPE_BUF规定了内核中管道缓冲区的大小。如果多个进程同时写一个管道(或者FIFO),要保证写的字节数不大于PIPE_BUF,这样多个写进程的数据不会相互穿插而造成混乱
4)open使用O_NONBLOCK 旗标时,打开FIFO 文件来读取的操作会立刻返回,但是若还没有其他进程打开FIFO 文件来读取,则写入的操作会返回ENXIO 错误代码。没有使用O_NONBLOCK 旗标时,打开FIFO 来读取的操作会等到其他进程打开FIFO文件来写入才正常返回。同样地,打开FIFO文件来写入的操作会等到其他进程打开FIFO 文件来读取后才正常返回。
xxxxxxxxxx71|(竖线)为管道,是两个进程之间的通信通道2例如:ls|grep txt3ls和grep由|分开,管道创建了程序之间的通信通道,将ls的输出作为输入传给grep45由mkfifo创建出来的就是一个命名管道6例如:mkfifo pipe27pipe2就是一个命名管道。
xxxxxxxxxx161[root@servera ~]# mkfifo --help2Usage: mkfifo [OPTION]... NAME...3Create named pipes (FIFOs) with the given NAMEs.4
5Mandatory arguments to long options are mandatory for short options too.6 -m, --mode=MODE set file permission bits to MODE, not a=rw - umask7 -Z set the SELinux security context to default type8 --context[=CTX] like -Z, or if CTX is specified then set the SELinux9 or SMACK security context to CTX10 --help display this help and exit11 --version output version information and exit12
13GNU coreutils online help: <https://www.gnu.org/software/coreutils/>14Full documentation at: <https://www.gnu.org/software/coreutils/mkfifo>15or available locally via: info '(coreutils) mkfifo invocation'16
可以将输出信道化到不同终端、
xxxxxxxxxx61例如:2在第一个终端执行3ls > pipe24在第二个终端执行5cat < pipe2(或cat pipe2,是取一次。cat < pipe2是持续输入,只要有内容传到pipe2中,就会有内容输出)6pipe2更像是一个临时存储的地方,使用cat pipe2取过内容之后,再执行cat pipe2 ,则不会有显示
xxxxxxxxxx321lsof abc.txt 显示开启文件abc.txt的进程2lsof -c abc 显示abc进程现在打开的文件3lsof -c -p 1234 列出进程号为1234的进程所打开的文件4lsof -g gid 显示归属gid的进程情况5lsof +d /usr/local/ 显示目录下被进程开启的文件6lsof +D /usr/local/ 同上,但是会搜索目录下的目录,时间较长7lsof -d 4 显示使用fd为4的进程8lsof -i 用以显示符合条件的进程情况9lsof -i[46] [protocol][@hostname|hostaddr][:service|port]10 46 --> IPv4 or IPv611 protocol --> TCP or UDP12 hostname --> Internet host name13 hostaddr --> IPv4地址14 service --> /etc/service中的 service name (可以不止一个)15 port --> 端口号 (可以不止一个)16
17lsof `which httpd` //那个进程在使用apache的可执行文件18lsof /etc/passwd //那个进程在占用/etc/passwd19lsof /dev/hda6 //那个进程在占用hda620lsof /dev/cdrom //那个进程在占用光驱21lsof -c sendmail //查看sendmail进程的文件使用情况22lsof -c courier -u ^zahn //显示出那些文件被以courier打头的进程打开,但是并不属于用户zahn23lsof -p 30297 //显示那些文件被pid为30297的进程打开24lsof -D /tmp 显示所有在/tmp文件夹中打开的instance和文件的进程。但是symbol文件并不在列25lsof -u1000 //查看uid是100的用户的进程的文件使用情况26lsof -utony //查看用户tony的进程的文件使用情况27lsof -u^tony //查看不是用户tony的进程的文件使用情况(^是取反的意思)28lsof -i //显示所有打开的端口lsof -i:80 //显示所有打开80端口的进程29lsof -i -U //显示所有打开的端口和UNIX domain文件30lsof -i UDP@[url]www.akadia.com:123 //显示那些进程打开了到www.akadia.com的UDP的123(ntp)端口的链接31lsof -i [email protected]:ftp -r //不断查看目前ftp连接的情况(-r,lsof会永远不断的执行,直到收到中断信号,+r,lsof会一直执行,直到没有档案被显示,缺省是15s刷新)32lsof -i [email protected]:ftp -n //lsof -n 不将IP转换为hostname,缺省是不加上-n参数
要与Linux交互,脚本获取键盘输入的结果是必不可少的,read可以读取键盘输入的字符。
read [-rs] [-a ARRAY] [-d delim] [-n nchars] [-N nchars] [-p prompt] [-t timeout] [var_name1 var_name2 ...]
read命令用于从标准输入中读取输入单行,并将读取的单行根据IFS变量分裂成多个字段,并将分割后的字段分别赋值给指定的变量列表var_name。第一个字段分配给第一个变量var_name1,第二个字段分配给第二个变量var_name2,依次到结束。如果指定的变量名少于字段数量,则多出的字段数量也同样分配给最后一个var_name,如果指定的变量命令多于字段数量,则多出的变量赋值为空。
如果没有指定任何var_name,则分割后的所有字段都存储在特定变量REPLY中。
xxxxxxxxxx91选项说明:2-a:将分裂后的字段依次存储到指定的数组中,存储的起始位置从数组的index=0开始。3-d:指定读取行的结束符号。默认结束符号为换行符。4-n:限制读取N个字符就自动结束读取,如果没有读满N个字符就按下回车或遇到换行符,则也会结束读取。5-N:严格要求读满N个字符才自动结束读取,即使中途按下了回车或遇到了换行符也不结束。其中换行符或回车算一个字符。6-p:给出提示符。默认不支持"\n"换行,要换行需要特殊处理,见下文示例。例如,"-p 请输入密码:"7-r:禁止反斜线的转义功能。这意味着"\"会变成文本的一部分。8-s:静默模式。输入的内容不会回显在屏幕上。9-t:给出超时时间,在达到超时时间时,read退出并返回错误。也就是说不会读取任何内容,即使已经输入了一部分。
使用示例:
(1).将读取的内容分配给数组变量,从索引号0开始分配。
xxxxxxxxxx81[root@xuexi ~]# read -a array_test2what is you name?34[root@xuexi ~]# echo ${array_test[@]}5what is you name?67[root@xuexi ~]# echo ${array_test[0]}8what
(2).指定读取行的结束符号,而不再使用换行符。
xxxxxxxxxx21[root@xuexi ~]# read -d '/'2what is you name \// # 输入完尾部的"/",自动结束read
由于没有指定var_name,所以通过$REPLY变量查看read读取的行。
xxxxxxxxxx21[root@xuexi ~]# echo $REPLY2what is you name /
(3).限制输入字符。
例如,输入了5个字符后就结束。
xxxxxxxxxx51[root@xuexi tmp]# read -n 521234534[root@xuexi tmp]# echo $REPLY # 输入12345共5个字符512345
如果输入的字符数小于5,按下回车会立即结束读取。
xxxxxxxxxx51[root@xuexi ~]# read -n 5212334[root@xuexi ~]# echo $REPLY5123
但如果使用的是"-N 5"而不是"-n 5",则严格限制读满5个字符才结束读取。
xxxxxxxxxx61[root@xuexi ~]# read -N 52123\n434[root@xuexi ~]# read -N 55123 # 3后的回车(换行)算是一个字符64
(4).使用-p选项给出输入提示。
xxxxxxxxxx51[root@xuexi ~]# read -p "pls enter you name: "2pls enter you name: Junmajinlong34[root@xuexi ~]# echo $REPLY5Junmajinlong
"-p"选项默认不带换行功能,且也不支持"\n"换行。但通过$'string'的方式特殊处理,就可以实现换行的功能。例如:
xxxxxxxxxx31[root@node2 ~]# read -p $'Enter your name: \n'2Enter your name:3JunMaJinLong
关于$'String'和$"String"的作用如下:
有些时候在某些服务管理脚本中看到
$"$string"或$"string",经过一些测试,又发现引号外面的$有和没有是一样的。一直也没去找究竟,刚才有人问了我,于是就去翻了下man bash,找到了解释。(1).如果没有特殊定制bash环境或有特殊需求,
""只是为了保证本地化。 以下是man bash关于$""的解释:
xxxxxxxxxx21A double-quoted string preceded by a dollar sign ($"string") will cause the string to be translated according to the current locale. If2the current locale is C or POSIX, the dollar sign is ignored. If the string is translated and replaced, the replacement is double-quoted.(2).还有
'string',这在bash中被特殊对待:会将某些反斜线序列(如\n,\t,",'等)继续转义,而不认为它是字面符号(如果没有$符号,单引号会强制将string翻译为字面符号,包括反斜线)。简单的例子: xxxxxxxxxx51[root@xuexi ~]# echo 'a\nb'2a\nb3[root@xuexi ~]# echo $'a\nb'4a5b以下是man bash里关于$'的说明:
xxxxxxxxxx191Words of the form $'string' are treated specially. The word expands to string, with backslash-escaped characters replaced as specified by the ANSI C standard. Backslash escape sequences, if present, are decoded as follows:2\a alert (bell)3\b backspace4\e5\E an escape character6\f form feed7\n new line8\r carriage return9\t horizontal tab10\v vertical tab11\\ backslash12\' single quote13\" double quote14\nnn the eight-bit character whose value is the octal value nnn (one to three digits)15\xHH the eight-bit character whose value is the hexadecimal value HH (one or two hex digits)16\uHHHH the Unicode (ISO/IEC 10646) character whose value is the hexadecimal value HHHH (one to four hex digits)17\UHHHHHHHH18the Unicode (ISO/IEC 10646) character whose value is the hexadecimal value HHHHHHHH (one to eight hex digits)19\cx a control-x character
(5).禁止反斜线转义功能。
xxxxxxxxxx51[root@xuexi ~]# read -r2what is you name \?34[root@xuexi ~]# echo $REPLY5what is you name \?
(6).不回显输入的字符。比如输入密码的时候,不回显输入密码。
xxxxxxxxxx51[root@xuexi ~]# read -s -p "please enter your password: "2please enter your password:34[root@xuexi ~]# echo $REPLY5123456
另一种方法
xxxxxxxxxx712stty -echo 3read -p "输入密码:" pwd 4stty echo 5echo 6echo 输入完毕。7其中,选项-echo禁止将输出发送到终端,而选项echo则允许发送输出。(7).将读取的行分割后赋值给变量。
xxxxxxxxxx51[root@xuexi ~]# read var1 var2 var32abc def galsl djks34[root@xuexi ~]# echo $var1:::$var2:::$var35abc:::def:::galsl djks
(8).给出输入时间限制。没完成的输入将被丢弃,所以变量将赋值为空(如果在执行read前,变量已被赋值,则此变量在read超时后将被覆盖为空)。
xxxxxxxxxx61[root@xuexi ~]# var=523[root@xuexi ~]# read -t 3 var4156[root@xuexi ~]# echo $var
(9).读文件
xxxxxxxxxx61count=12cat /etc/fstab | while read line3do4 echo "Line ${count}:${line}"5 count=$[ $count + 1 ]6done
xxxxxxxxxx151File=/etc/passwd2{3read line14read line25} < $File6
7echo "First line in ${File}"8echo "${line1}"9
10echo "----------"11
12echo "Second line in ${File}"13echo "${line2}"14
15
xxxxxxxxxx7012# assign the file descriptor to file for input fd # 3 is Input file3exec 3< test.txt4 5# read the file using fd # 36count=07while read -u 3 var8do9 let count=$count+110 echo "Line $count:$var"11done12echo "finished"13echo "Line no is $count"14 15# Close fd # 316exec 3<&-17
18
1920count=121cat test.txt | while read line22do23 echo "Line $count:$line"24 let count=$count+125done26echo "finished"27echo "Line no is $count"28exit 029
30# 执行效果31[roc@roclinux ~]$ ./test.sh32Line 1:1924833Line 2:1924734Line 3:1924635finished36Line no is 137
38咦,有个问题。脚本最后输出的是 Line no is 1,怎么行数是 1 呢,明明是 3 才对啊?39上面这个问题,是由于管道导致的。我们知道,管道的两边一般需要新建进程,当执行完 while 语句后,新进程也就结束了。而脚本中 count 是新进程中的自定义变量,进程结束后该变量也就消失了(自定义变量的生命周期结束)。当脚本执行 echo 时,显示的 count 变量是脚本中第一行定义的变量的值,而不是 while 语句中的那个 count 变量了,因而输出的结果当然就是 1 了。40
41
4243count=044while read line45do46 let count=$count+147 echo "Line $count:$line"48done < test.txt49echo "finished"50echo "Line no is $count"51exit 052
53
5455# assign the file descriptor to file for input fd # 3 is Input file56exec 3< test.txt57 58# read the file using fd # 359count=060while read -u 3 -r var61do62 let count=$count+163 echo "Line $count:$var"64done65echo "finished"66echo "Line no is $count"67 68 69# Close fd # 370exec 3<&-xxxxxxxxxx831lsof abc.txt 显示开启文件abc.txt的进程2lsof -c abc 显示abc进程现在打开的文件3lsof -c -p 1234 列出进程号为1234的进程所打开的文件4lsof -g gid 显示归属gid的进程情况5lsof +d /usr/local/ 显示目录下被进程开启的文件6lsof +D /usr/local/ 同上,但是会搜索目录下的目录,时间较长7lsof -d 4 显示使用fd为4的进程8lsof -i 用以显示符合条件的进程情况9lsof -i[46] [protocol][@hostname|hostaddr][:service|port]10 46 --> IPv4 or IPv611 protocol --> TCP or UDP12 hostname --> Internet host name13 hostaddr --> IPv4地址14 service --> /etc/service中的 service name (可以不止一个)15 port --> 端口号 (可以不止一个)16 17
18lsof -a // 默认多个条件组合时,lsof使用OR逻辑,而使用-a表示AND逻辑。19lsof `which httpd` //那个进程在使用apache的可执行文件20lsof /etc/passwd //那个进程在占用/etc/passwd21lsof /dev/hda6 //那个进程在占用hda622lsof /dev/cdrom //那个进程在占用光驱23lsof -c sendmail //查看sendmail进程的文件使用情况24lsof -c courier -u ^zahn //显示出那些文件被以courier打头的进程打开,但是并不属于用户zahn25lsof -p 30297 //显示那些文件被pid为30297的进程打开26lsof -D /tmp 显示所有在/tmp文件夹中打开的instance和文件的进程。但是symbol文件并不在列27
28lsof -u1000 //查看uid是100的用户的进程的文件使用情况29lsof -utony //查看用户tony的进程的文件使用情况30lsof -u^tony //查看不是用户tony的进程的文件使用情况(^是取反的意思)31lsof -i //显示所有打开的端口32lsof -i:80 //显示所有打开80端口的进程33lsof -i -U //显示所有打开的端口和UNIX domain文件34lsof -i UDP@[url]www.akadia.com:123 //显示那些进程打开了到www.akadia.com的UDP的123(ntp)端口的链接35lsof -i [email protected]:ftp -r //不断查看目前ftp连接的情况(-r,lsof会永远不断的执行,直到收到中断信号,+r,lsof会一直执行,直到没有档案被显示,缺省是15s刷新)36lsof -i [email protected]:ftp -n //lsof -n 不将IP转换为hostname,缺省是不加上-n参数37
38lsof -a -p $$39
40
41is the File Descriptor number of the file or:42
43 cwd current working directory;44 Lnn library references (AIX);45 err FD information error (see NAME column);46 jld jail directory (FreeBSD);47 ltx shared library text (code and data);48 Mxx hex memory-mapped type number xx.49 m86 DOS Merge mapped file;50 mem memory-mapped file;51 mmap memory-mapped device;52 pd parent directory;53 rtd root directory;54 tr kernel trace file (OpenBSD);55 txt program text (code and data);56 v86 VP/ix mapped file;57
58FD is followed by one of these characters, describing the mode under which the file is open:59
60 r for read access;61 w for write access;62 u for read and write access;63 space if mode unknown and no lock64 character follows;65 `-' if mode unknown and lock66 character follows.67
68The mode character is followed by one of these lock characters, describing the type of lock applied to the file:69
70 N for a Solaris NFS lock of unknown type;71 r for read lock on part of the file;72 R for a read lock on the entire file;73 w for a write lock on part of the file;74 W for a write lock on the entire file;75 u for a read and write lock of any length;76 U for a lock of unknown type;77 x for an SCO OpenServer Xenix lock on part of the file;78 X for an SCO OpenServer Xenix lock on the entire file;79 space if there is no lock.80
81See the LOCKS section for more information on the lock information character.82
83The FD column contents constitutes a single field for parsing in post-processing scripts.
循环实现并发程序:
并发的实现原理是将进程放到后台运行,从而不影响当前shell的运行。在shell脚本中有&符号可以实现这个操作。
xxxxxxxxxx1212echo "hello multiprocess"3
4for ((i=0;i<10;i++))5do6 {7 echo $i8 sleep 29 }&10done11wait # 等待子进程结束,类似于高级语言的线程同步12echo "process end"上述脚本已经可以产生并发的效果,但是如果并发数量过于庞大,那么系统将无法处理,你将看到系统CPU负载极高的直观现象。
程序的并发数量并不是无限的,进程过多会导致机器卡死,所以需要控制并发的数量。可以使用管道来实现控制并发的数量。
原理:
linux管道文件特性制作队列,控制线程数目
1.管道具有存一个读一个,读完一个就少一个,没有则阻塞,放回的可以重复取,这正是队列特性,但是问题是当往管道文件里面放入一段内容,没人取则阻塞,这样你永远也没办法往管道里面同时放入10段内容(想当与10把钥匙),解决这个问题的关键就是文件描述符了。
2.mkfifo /tmp/fd1
创建有名管道文件exec 3<>/tmp/fd1,创建文件描述符3关联管道文件,这时候3这个文件描述符就拥有了管道的所有特性,还具有一个管道不具有的特性:无限存不阻塞,无限取不阻塞,而不用关心管道是否为空。也不用关心是否有内容写入引用文件描述符:&3可以执行n次echo >&3往管道里放入n次内容
xxxxxxxxxx2712echo "hello multiprocess"3process=54tmp_fifofile=/tmp/$$.fifo # 使用当前pid作为管道文件名称,防止文件名称冲突5mkfifo ${tmp_fifofile} # 创建管道文件6exec 9<> ${tmp_fifofile} # 读写方式打开文件并将文件描述符设置为97rm -rf ${tmp_fifofile} # 删除管道文件,注:这一操作不会影响文件描述符8
9for i in `seq $process`10do11 echo >&9 # 向文件描述符传递5个空行12done13
14for i in {1..10}15do16 read -u 9 # 读取管道内容,每次读取一行17 {18 echo $i # 显示当前值19 sleep 1 # 使用程序延时20 echo >&9 # 程序结束追加空行21 }&22done23
24wait # 等待子进程结束,类似于高级语言的线程同步25exec 9>&- # 释放文件描述符26exec 9<&-27echo "process end"其中
xxxxxxxxxx61exec fd< file # 以只读方式打开文件,并关联文件描述符fd2exec fd> file # 以只写方式打开文件,并关联文件描述符fd3exec fd<>file # 以读写方式打开文件,并关联文件描述符fd4
5read -u fd # 读取文件描述符fd,关联其中一行内容,即一次只读去文件描述符fd一行6