首页 > 系统服务 > 详细

脚本shell

时间:2017-09-04 23:57:39      阅读:374      评论:0      收藏:0      [点我收藏+]

一:基础介绍

1优先级

别名-->内部命令-->外部命令

2. 脚本调试

sh  -x  foo.sh

sh  -e  foo.sh

3三种定界符

"字符串。。。。$变量名"   #双引号用于界定不连续的字符,支持变量

字符串。。。。$ # ?‘        #单引号无法引用变量

`command`   或者  $(command)  【命令替换】  #反撇号用于执行命令,等同于$()

二:运算

1 Shell整数运算

 

方法1

    expr  表达式

 

方法2

     echo  $[表达式]

     echo  $((表达式))

自增运算

let  A++  或者  ((A++))

let  表达式      或者     ((表达式))

 

2小数用管道交给 bc

echo  "表达式"  |  bc

三:变量

1 变量基本操作 ——

变量名=

echo  $变量名

2 变量的几种类型 ——

自定义变量

环境变量:变量名一般全大写字母、用户登录后自动设好

位置变量:$1$2$3。。。。${10}。。。

预定义变量:

$0表示Shell本身的文件名,$#表示变量的个数,$*将所有位置变量作为一个整体,$@

将所有位置变量作为一个字符串,$! 表示最后运行的后台ProcessPID$? 表示返回值

3 read -p "请输入你的名字:" name#输入的数值将赋值给变量name

四: 条件判断与循环

1 文件和目录的状态测试

-e filename如果 filename存在,则为真[ -e /var/log/syslog ]

-d filename如果 filename为目录,则为真[ -d /tmp/mydir ]

-f filename如果 filename为常规文件,则为真[ -f /usr/bin/grep ]

-r filename如果 filename可读,则为真[ -r /var/log/syslog ]

-w filename如果 filename可写,则为真[ -w /var/mytmp.txt ]

-x filename如果 filename可执行,则为真[ -x /usr/bin/grep ]

-s filename如果文件有数据,则为真[ -s /etcpasswd ]

#方括号和数据之间必须有空格,前面加!表示取反[ ! -x /usr/bin/grep ]

2 整数值比较:

num1-eq num2等于[ 3 -eq $mynum ]

num1-ne num2不等于[ 3 -ne $mynum ]

num1-lt num2小于[ 3 -lt $mynum ]

num1-le num2小于或等于[ 3 -le $mynum ]

num1-gt num2大于[ 3 -gt $mynum ]

num1-ge num2大于或等于[ 3 -ge $mynum ]

3 字符串比较:

-z string如果 string长度为零,则为真[ -z "$myvar" ]

-n string如果 string长度非零,则为真[ -n "$myvar" ]

string1== string2如果 string1string2相同,则为真[ "$myvar" == "one two three" ]

string1!= string2如果 string1string2不同,则为真[ "$myvar" != "one two three" ]

&&  ||   

4 函数及中断控制

break  放弃当前的整个循环语句,---》跳到done之后

continue  放弃当前这一次循环语句,---》返回while [ 测试条件 ]

exit  退出当前的整个脚本

shift  处理位置变量

 

5  if选择结构 ——

单分支:

if  [ 条件测试 ];

then

    命令序列....

fi

双分支:

if  [ 条件测试 ]

then

    命令序列1....

else

    命令序列2....

fi

多分支:

if  [ 条件测试1 ]

then

    命令序列1....

elif  [ 条件测试2 ]

then

        命令序列2....

else

        命令序列3....

fi

6  for循环结构 ——

for  变量名  in   1   2  3 ....

do

     命令序列....

done

4 while循环结构 ——

while  [ 条件测试 ]

do

     命令序列....

Done

7   当条件成立的时候结束循环

until  [ .. .. ]

do

    cmd1 .. ..

done

 

8 C语言风格的for循环

for  ((i=1;i<10;i++))

do

     cmd1 .. ..

Done

9  case分支

case  $1  in

模式1)

    cmd1 .. ..

    ;;

模式2)

    cmd2 .. ..

    ;;

.. ..

*)

    cmd n .. ..

esac

10 例子(添加用户)

[root@stu day03]# cat uadm.sh

#!/bin/bash

if [ "$1" == "--add" ] && [ -f "$2" ]

then

for UNAME in $(cat $2)

do

useradd $UNAME

echo 123456 | passwd --stdin $UNAME

chage -d 0 $UNAME

done

elif [ "$1" == "--del" ] && [ -f "$2" ]

then

for UNAME in $(cat $2)

do

userdel -r $UNAME

done

else

echo "Usage: $0 --add|--del users.txt"

exit 1

Fi

: 子字符串截取 及变量附初值

1 [root@stu day03]# var1="CentOS6.5"

[root@stu day03]# echo ${var1:6:3}

6.5

[root@stu day03]# expr substr "$var1" 7 3

6.5

[root@stu day03]# echo "$var1" | cut -c 7-9

6.5

 

2 ${var1:起始位置:长度}

${var1::长度} 【从第0个字符开始截取...

${var1:起始位置}  ..截取到末尾】

${var1:0-起始位置:长度}  0-倒数位置】

${var1:0-起始位置} 0-倒数位置】

 

3 echo $var1 | cut  -c  起始位置-结束位置

echo $var1 | cut  -c  -结束位置

echo $var1 | cut  -c  起始位置-

echo $var1 | cut  -c  字符位置

echo $var1 | cut  -c  位置1,位置2.. ..

 

echo $var1 | cut  -d "分隔字符"  -f  起始字段-结束字段

.. ..

echo $var1 | cut  -d "分隔字符"  -f  字段1,字段2.. ..

 

4 echo ${#var1} 【获取变量值长度】

 

 

5 子字符串替换 ——

${var/old/new}【只替换第一个】

${var//old/new} 【替换全部】

 

6 字符串的掐头去尾——

${变量名#*关键词}【最小匹配】

${变量名##*关键词}  【最大匹配】

${变量名%*关键词}【最小匹配】

${变量名%%*关键词}  【最大匹配】

# % 的左边

7 basename  "文档路径" 【取文档名称】

dirname  "文档路径" 【取文档的存放目录】

8 变量初值

${var1:-}

${var1:=}

六:函数

如何定义一个函数 ——

1 函数名() {

    cmd .. ..

}

 -- 或者 --

2 function  函数名 {

    cmd .. ..

}

 

如何使用一个函数 ——

函数名

函数名  参数1  参数2

 

#!/bin/bash

name () {

sum=`expr $0 + $2`

echo $sum

}

name $1  $2

3 例子(生成mac地址)

#!/bin/bash

macgen() {

  MAC="00:0c"

  for ((i=1;i<=4;i++))

  do

    MAC=$MAC":$(uuidgen | cut -b -2)"

  done

  echo $MAC

}

macgen

七:启动脚本编写

1 编写系统服务脚本 ——

# vim  /etc/init.d/服务名

#!/bin/bash

# chkconfig: 运行级别  启动顺序  停止顺序

# description: 关于本服务的描述

.. ..

 

2 chkconfig  --add  服务脚本名

3 序列问题

rev:以字符为单位倒序输出文本

tac:以行为单位倒序输出文本

八:expect (非交互)

1  expect常用指令 ——

#!/bin/bash

spawn  交互进程

expect  "期望的文本1"  { send "提交的文本1\r" }

expect  "期望的文本2"  { send "提交的文本2\r" }

.. ..

expect  eofEnd of File

#interact

2  如何将expect指令合成到shell脚本当中vb——

#!/bin/bash

.. .. Shell语句

expect  -  <<EOF

.. .. expect语句

.. ..

EOF

.. .. Shell语句

3 远程登陆脚本

 #!/bin/bash

host=192.168.4.5

user=mike

password="123456"

#expect -f exp.txt

expect - <<EOF

spawn ssh $user@$host

expect {

  "(yes/no)?" { send "yes\r" ; exp_continue}

  "password:" { send "$password\r" }

}

expect "\[$user\@" { send "pwd > /tmp/$user.txt ; exit\r" }

expect eof

EOF

正则表达式

1 非打印字符

推荐使用egrep而不采用grep -e

cx匹配由x指明的控制字符。例如, \cM 匹配一个 Control-M 或回车符。x 的值必须为 A-Z a-z 之一。否则,将 c 视为一个原义的 ‘c‘ 字符。

\f匹配一个换页符。等价于 \x0c \cL

\n匹配一个换行符。等价于 \x0a \cJ

\r匹配一个回车符。等价于 \x0d \cM

\s匹配任何空白字符,包括空格、制表符、换页符等等。等价于 [ \f\n\r\t\v]

\S匹配任何非空白字符。等价于 [^ \f\n\r\t\v]

\t匹配一个制表符。等价于 \x09 \cI

\v匹配一个垂直制表符。等价于 \x0b \cK

echo -e "aaaaaa\nbbbbbb"

echo -e "aaaaaa\tbbbbbb"

echo -e "aaaaaa\vbbbbbb"

echo -e "aadddddddddda\vbbb\t\tccc\nddd"

2 特殊字符

所谓特殊字符,就是一些有特殊含义的字符,若要匹配这些特殊字符,必须首先使字符"转义",即,将反斜杠字符 (\) 放在它们前面。

$匹配输入字符串的结尾位置。如果设置了 RegExp 对象的 Multiline 属性,则 $ 也匹配 ‘\n‘ ‘\r‘。要匹配 $ 字符本身,请使用 \$

( )标记一个子表达式的开始和结束位置。子表达式可以获取供以后使用。要匹配这些字符,请使用 \( \)

*匹配前面的子表达式零次或多次。要匹配 * 字符,请使用 \*

+匹配前面的子表达式一次或多次。要匹配 + 字符,请使用 \+

.匹配除换行符 \n之外的任何单字符。要匹配 .,请使用 \

[标记一个中括号表达式的开始。要匹配 [,请使用 \[

?匹配前面的子表达式零次或一次,或指明一个非贪婪限定符。要匹配 ? 字符,请使用 \?

\将下一个字符标记为或特殊字符、或原义字符、或向后引用、或八进制转义符。例如, ‘n‘ 匹配字符 ‘n‘‘\n‘ 匹配换行符。序列 ‘\\‘ 匹配 "\",而 ‘\(‘ 则匹配 "("

^匹配输入字符串的开始位置,除非在方括号表达式中使用,此时它表示不接受该字符集合。要匹配 ^ 字符本身,请使用 \^

{标记限定符表达式的开始。要匹配 {,请使用 \{

|指明两项之间的一个选择。要匹配 |,请使用 \|

{n}n 是一个非负整数。匹配确定的 n 次。例如,‘o{2}‘ 不能匹配 "Bob" 中的 ‘o‘,但是能匹配 "food" 中的两个 o

{n,}n 是一个非负整数。至少匹配n 次。例如,‘o{2,}‘ 不能匹配 "Bob" 中的 ‘o‘,但能匹配 "foooood" 中的所有 o‘o{1,}‘ 等价于 ‘o+‘‘o{0,}‘ 则等价于 ‘o*‘

{n,m}m n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,"o{1,3}" 将匹配 "fooooood" 中的前三个 o‘o{0,1}‘ 等价于 ‘o?‘。请注意在逗号和两个数之间不能有空格。

\b匹配一个字边界,即字与空格间的位置。

\B非字边界匹配。

确定重复出现

^[a-zA-Z_]$所有的字母和下划线

^[[:alpha:]]{3}$所有的3个字母的单词

\t{2}两个制表符

(pattern)匹配 pattern 并获取这一匹配。所获取的匹配可以从产生的 Matches 集合得到,在VBScript 中使用 SubMatches 集合,在JScript 中则使用 $0$9 属性。要匹配圆括号字符,请使用 ‘\(‘ ‘\)‘

(?:pattern)匹配 pattern 但不获取匹配结果,也就是说这是一个非获取匹配,不进行存储供以后使用。这在使用 "" 字符 (|) 来组合一个模式的各个部分是很有用。例如, ‘industr(?:y|ies) 就是一个比 ‘industry|industries‘ 更简略的表达式。

(?=pattern)正向预查,在任何匹配 pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如,‘Windows (?=95|98|NT|2000)‘ 能匹配 "Windows 2000" 中的 "Windows" ,但不能匹配 "Windows 3.1" 中的 "Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。

(?!pattern)负向预查,在任何不匹配 pattern 的字符串开始处匹配查找字符串。这是一个非获取匹配,也就是说,该匹配不需要获取供以后使用。例如‘Windows (?!95|98|NT|2000)‘ 能匹配 "Windows 3.1" 中的 "Windows",但不能匹配 "Windows 2000" 中的 "Windows"。预查不消耗字符,也就是说,在一个匹配发生后,在最后一次匹配之后立即开始下一次匹配的搜索,而不是从包含预查的字符之后开始。

x|y匹配 x y。例如,‘z|food‘ 能匹配 "z" "food"‘(z|f)ood‘ 则匹配 "zood" "food"

[xyz]字符集合。匹配所包含的任意一个字符。例如, ‘[abc]‘ 可以匹配 "plain" 中的 ‘a‘

[^xyz]负值字符集合。匹配未包含的任意字符。例如, ‘[^abc]‘ 可以匹配 "plain" 中的‘p‘‘l‘‘i‘‘n‘

[a-z]字符范围。匹配指定范围内的任意字符。例如,‘[a-z]‘ 可以匹配 ‘a‘ ‘z‘ 范围内的任意小写字母字符。

[^a-z]负值字符范围。匹配任何不在指定范围内的任意字符。例如,‘[^a-z]‘ 可以匹配任何不在 ‘a‘ ‘z‘ 范围内的任意字符。

 

\D匹配一个非数字字符。等价于 [^0-9]

 

\w匹配包括下划线的任何单词字符。等价于‘[A-Za-z0-9_]‘

\W匹配任何非单词字符。等价于 ‘[^A-Za-z0-9_]‘

\xn匹配 n,其中 n 为十六进制转义值。十六进制转义值必须为确定的两个数字长。例如,‘\x41‘ 匹配 "A"‘\x041‘ 则等价于 ‘\x04‘ & "1"。正则表达式中可以使用 ASCII 编码。

\num匹配 num,其中 num 是一个正整数。对所获取的匹配的引用。例如,‘(.)\1‘ 匹配两个连续的相同字符。

\n标识一个八进制转义值或一个向后引用。如果 \n 之前至少 n 个获取的子表达式,则 n 为向后引用。否则,如果 n 为八进制数字 (0-7),则 n 为一个八进制转义值。

\nm标识一个八进制转义值或一个向后引用。如果 \nm 之前至少有 nm 个获得子表达式,则 nm 为向后引用。如果 \nm 之前至少有 n 个获取,则 n 为一个后跟文字 m 的向后引用。如果前面的条件都不满足,若 n m 均为八进制数字 (0-7),则 \nm 将匹配八进制转义值 nm

\nml如果 n 为八进制数字 (0-3),且 m l 均为八进制数字 (0-7),则匹配八进制转义值 nml

\un匹配 n,其中 n 是一个用四个十六进制数字表示的 Unicode 字符。例如, \u00A9 匹配版权符号 (?)

cat /etc/passwd | egrep "\bin"#in位于单词的首

cat /etc/passwd | egrep "in\b"#in位于单词的尾

cat /etc/passwd | egrep "\Bin"#in不位于单词的首

cat /etc/passwd | egrep "in\B"#in不位于单词的尾

cat /etc/passwd | egrep "o{1,3}"cat /etc/passwd | egrep "o{2,3}"cat /etc/passwd | egrep "o{2,}"

cat /etc/passwd | egrep ^root

cat /etc/passwd | grep -e bash$

cat /etc/passwd | egrep  oo* | wc -lcat /etc/passwd | egrep  \(oo\)* | wc -l#后者多是因为将oo看作一个整体

cat /etc/passwd | egrep r.tcat /etc/passwd | egrep r..t

cat /etc/passwd | egrep "t\w*d"cat /etc/passwd | egrep "t\w+d"cat /etc/passwd | egrep "t\w?d"#*+多一个0

 

3 邮件过滤

abc@def.com

abc@def.hij.com

          [a-z0-9]+    \.    [a-z0-9]{2,4}

          ([a-z0-9]+\.){1,3}   [a-z0-9]{2,4}

十:sed

1 sed 处理文本的两种方式 ——

sed  [选项]  ‘[定址符]处理动作‘  文本文件...

其他命令 | sed  [选项]  ‘[定址符]处理动作

 

常用的选项 ——

-n :使用安静(silent)模式。在一般 sed 的用法中,所有来自 STDIN 的数据一般都会被列出到终端上。但如果加上 -n 参数后,则只有经过sed 特殊处理的那一行(或者动作)才会被列出来。

-e :直接在命令列模式上进行 sed 的动作编辑;

-f :直接将 sed 的动作写在一个文件内, -f filename 则可以运行 filename 内的 sed 动作;

-r sed 的动作支持的是延伸型正规表示法的语法。(默认是基础正规表示法语法)

-i :直接修改读取的文件内容,而不是输出到终端。

2 定址符的写法 ——

 sed -i ‘/gpgcheck/s/\(gpgcheck\)/#(\1)/g‘ CentOS-*

行号

行号1,行号2

正则表达式

行号1,正则表达式

正则表达式,行号2

5,~7从第5行开始,到下一个7的倍数行结束

5~7取每7行当中的第5

5~5取每5行当中的第5

7~5从第7行开始,以后取每5行的第5

 

常用的处理动作 ——

n1, n2 :不见得会存在,一般代表『选择进行动作的行数』,举例来说,如果我的动作是需要在 10 20 行之间进行的,则『 10,20[动作行为]

a :新增,a 的后面可以接字串,而这些字串会在新的一行出现(目前的下一行)

c :取代,c 的后面可以接字串,这些字串可以取代 n1,n2 之间的行

d :删除,因为是删除,所以 d 后面通常不接任何字符

i :插入,i 的后面可以接字串,而这些字串会在新的一行出现(目前的上一行)

p :列印,亦即将某个选择的数据印出。通常 p 会与参数 sed -n 一起运行

s :取代,可以直接进行取代的工作哩!通常这个 s 的动作可以搭配正规表示法rw

HhGg

 

egrep ‘[a-z0-9]{3,}@([a-z0-9]+\.){1,3}[a-z0-9]{2,4}‘ t4.txt

一一替换

Sed  y/abcdefghijklmnopqrstuvwlmn/ghijklmnopqrstuvwlmnabcdef/   /etc/passwd  即匹配一个替换一个

 

十一:awk

1  awk的内置变量

两种执行方式 ——

awk  -F:  ‘[条件]{编辑指令}‘   文件.. ..

其他命令 | awk  -F:  ‘[条件]{编辑指令}‘

ARGC               命令行参数个数

ARGV               命令行参数排列

ENVIRON            支持队列中系统环境变量的使用

FILENAME           awk浏览的文件名

FNR                浏览文件的记录数

FS                 设置输入域分隔符,等价于命令行 -F选项

NF                 浏览记录的域的个数

NR                 已读的记录数

OFS                输出域分隔符

ORS                输出记录分隔符

RS                 控制记录分隔符

awk ‘BEGIN{FS=":"}/^root/{print $1,$NF}‘ /etc/passwd#FS分隔符

awk ‘BEGIN{FS=":"}{print NR,$1,$NF}‘ /etc/passwd#NR行号,NF总列数

awk ‘BEGIN{FS=":";OFS="^^"}/^root/{print FNR,$1,$NF}‘ /etc/passwd#OFS输出分割数

awk  -F ‘:‘  ‘{print "文件名是:"FILENAME",这是第:"NR,此行一共有:"NF",此行全部内容为:"$0}‘ /etc/passwd

#默认分隔符为单个或多个tab和空格,$0表示整行,$1$3表示第1列和第三列,用逗号分隔

 

2 printprintf

awk中同时提供了printprintf两种打印输出的函数。

其中print函数的参数可以是变量、数值或者字符串。字符串必须用双引号引用,参数用逗号分隔。如果没有逗号,参数就串联在一起而无法区分。这里,逗号的作用与输出文件的分隔符的作用是一样的,只是后者是空格而已。

printf函数,其用法和c语言中printf基本相似,可以格式化字符串,输出复杂时,printf更加好用,代码更易懂。

awk  -F ‘:‘  ‘{printf("filename:%10s,linenumber:%s,columns:%s,linecontent:%s\n",FILENAME,NR,NF,$0)}‘ /etc/passwd

 

3  实验-可多重条件查找,输出多次

awk ‘BEGIN {FS=":"} ; /0/ {print $0} ; /root/ {print $0}‘ /etc/passwd

#查找到有0的行输出,查找到有root的行输出,//之间采用正则表达式,$0表示输出整行

 

变量和赋值

awk ‘{count++;print $0;} END{print "user count is ", count}‘ /etc/passwd

#count为变量,默认初始值为0。之前的action{}里都是只有一个print,其实print只是一个语句,而action{}可以有多个语句,以;号隔开

awk ‘BEGIN {count=0;print "[start]user count is ", count} {count=count+1;print $0;} END{print "[end]user count is ", count}‘ /etc/passwd

#count虽然默认是0,但是妥当的做法还是初始化为0

4  实验-支持正则表达式

awk ‘/11+/ {print $0}‘ qintest

awk ‘/oo+/ {print $0}‘ /etc/passwd | awk ‘/^r/ {print $0}‘

awk ‘/oo+|^root/ {print $0}‘ /etc/passwd

awk ‘/1{3,}/ {print $0}‘ qintest

awk ‘/1{4}/ {print $0}‘ qintest

awk ‘/1{2,3}/ {print $0}‘ qintest

 

实验-BEGINEND

cat /etc/passwd |awk  -F ‘:‘  ‘BEGIN {print "name\tshell"}  {print $1"\t"$7} END {print "nameend\tshellend"}‘

5  awk的流程控制 ——

经典去重 ——

awk ‘!x[$0]++‘ arr.txt

相当于 awk ‘!数组名[当前行的文本]{print $0}‘   arr.txt

 

第一次执行 x["/bin/bash"]++ 会失败

!x["/bin/bash"]++ 表示条件成立

第二、三……次执行 x["/bin/bash"]++ 会成功

!x["/bin/bash"]++ 表示条件不成立

 

 

6  awk文本处理练习:

 

1使用awk输出系统用户个数。

awk -F ":" ‘{j++}END{print j}‘ /etc/passwd

 

2使用awk输出系统内建用户个数。

awk -F ":" ‘$3<500{i++}END{print i}‘ /etc/passwd

 

3使用awk输出系统外建用户个数。

awk -F ":" ‘$3>500{j++}END{print j}‘ /etc/passwd

 

4使用awk 一次性 输出系统用户(UID<500)个数、其他用户个数、用户总数。

awk -F ":" ‘{i++}$3<500{j++}$3>=500{z++}END{print "user sum is  " i;print "inside user is "j;print "outside user is "z}‘ /etc/passwd

 

5 输出文件中 510行的行号和 对应行的内容。

awk -F ":" ‘FNR<=10&&FNR>=5{print $0}‘ /etc/passwd

 

6 输出文件中偶数行的行号 和 对应行的内容。

awk -F ":" ‘FNR%2==0{print FNR,$0}‘ /etc/passwd

 

7 输出文件 uid 值是 500的用户的详细信息

awk -F ":" ‘$3==500{print $0}‘ /etc/passwd

 

8 输出文件中 sync用户的详细信息

awk -F ":" ‘$1=="sync"{print $0}‘ /etc/passwd

 

9 输出数字3269之间,有数字7 或是 数字7 倍数的数。

seq 32 69|awk ‘$0~/7/ || $0%7==0{print $0}

 

10 统计不能登录系统的用户的个数

awk -F ":" ‘$7=="/sbin/nologin"{print $0}‘ /etc/passwd

 

11 查看uid号是5位数的用户的名字和uid号的值

awk -F ":" --posix ‘$3~/^[0-9]{3}$/{print $3}‘ /etc/passwd

awk -F ":" ‘$3~/...../{print $1,$3}‘ /etc/passwd

 

12 把名字里有数字的用户名输出。

awk -F ":" ‘$1~/[0-9]/{print $1}‘ /etc/passwd

 

13 输出文件前10行中的偶数行

awk -F ":" ‘FNR<=10&&FNR%2==0{print NR,$0}‘ /etc/passwd

 

 

 


本文出自 “13262050” 博客,请务必保留此出处http://13272050.blog.51cto.com/13262050/1962631

脚本shell

原文:http://13272050.blog.51cto.com/13262050/1962631

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!