shell文档处理三剑客(grep ||sed||awk)

grep ||sed||awk

Grep命令:

grep语法格式:

      grep [option] [pattern] [file1,file2...]

必须掌握的选项:

      -v   显示不匹配pattern的行

      -i    搜索时忽略大小写

      -n   显示行号

      -E   支持扩展的正则表达式

      -F   不支持正则表达式,按字符串的字面意思进行匹配

      -r    递归搜索

需了解的选项:

      -c   只输出匹配行的数量,不显示具体内容

      -w  匹配整词

      -x   匹配整行

      -l    只列出匹配的文件名,不显示具体匹配行内容

grep和egrep区别:

      grep默认不支持扩展正则表达式,只支持基础正则表达式

      使用grep -E可以支持扩展正则表达式

      使用egrep可以支持扩展正则表达式,与grep -E等价

举例:

查看不包括nologin的字符串,并显示行号

[root@ansible fang]# grep -nv "nologin" /etc/passwd

1:root:x:0:0:root:/root:/bin/bash

6:sync:x:5:0:sync:/sbin:/bin/sync

7:shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown

8:halt:x:7:0:halt:/sbin:/sbin/halt

43:fangqiming:x:1000:1000:fangqiming:/home/fangqiming:/bin/bash

[root@ansible fang]#

重点:

[pattern]正则表达式的使用

Sed命令:

sed语法(查询,删除,增加):

 

 

 

 

举例:

sed -n '/192.*/p' dd.yml

功能:将dd.yml文件中的包含192.的行打印出来,值打印匹配的行

sed –i ‘s/love/like/g’ sed.txt

功能:将sed.txt中所有love替换为like

将list.txt文件中的内容插入到匹配到的行后面

sed –i ‘/root/r list’ password

将sed匹配到的行内容写入到文件中

sed ‘/\/bin\/bash/w /tmp/user_login.txt’ passwd

 

将匹配到的内容对源文件进行替换为大写

Sed –i ‘s/\/bin\/bash/ \/BIN\/BASH/g’ passwd

将匹配到的内容,对源文件进行大写的修改,并且同一行内只替换前两个

Sed –i ‘s/root/ROOT/2g’ passwd

想匹配到的内容只显示行号

Sed –n ‘/\/sbin\/nologin/=’ passwd

其他编辑命令

 

其他的编辑命令

=     显示行号

反向引用:

&和\1       引用模式匹配到的整个串

Sed “s/1..e/&r/g” file 在file中搜寻以1开头,然后跟两个任意字符,以e结尾的字符串,用&代替搜寻到的字符串增加r字符后,对file进行修改

Sed “s/\(1..e\)/\1r/g” file  和上一条命令实现同样的功能,\1代表搜寻到的字符串

注意:   \1使用()对匹配到的字符串进行引用,如果只是想要替换匹配到的字符串的一部分,必须使用\1这种方式进行引用替换

反向引用

将正则匹配到的had..p的内容替换为had..ps   &表示引用前面整个字符串

将所有匹配到的had..p 后面家s

sed –i ‘s/had..p/&s/g’ str.txt

1也表示引用前面第一个()中的字符串,相对&更加灵活

sed –i ‘s/\(had..p\)/\1O/g’ str.txt

sed "s/\(l..e\)/\1r/g" file             和上面实现一样的功能,使用\1代表搜寻到的字符串

在脚本中使用sed注意事项

  1. 匹配模式中存在变量,则建议使用双引号
  2. Sed中需要引入自定义变量时,如果外面使用单引号,则自定义变量也必须使用单引号

引用变量的方式一

[root@ansible fang]# cat shell.sh

#!/bin/bash

#

old_str=fangqiming

new_str=FangQiMing

file="$1"

sed -i "s/$old_str/$new_str/g" $file

[root@ansible fang]# bash shell.sh 1.txt    执行

 

引用变量的方式二

#!/bin/bash

old_str=fangqiming

new_str=FangQiMing

file="$1"

sed -i 's/'$old_str'/'$new_str'/g' $file

这是在脚本中修改脚本内容的快捷方法

其实只是做的演示,如此简单的功能,我们在脚本中就可以实现拉,

当前行到最后一行,将所有的HADOOP替换为hadoop

:.,$s/Fang/fang/g

举例:

需求描述: 处理一个类似MYSQL配置文件my.cnf的文本,示例如下;

      编写脚本实现以下功能:输出文件有几段,并且针对每个段可以统计配置参数总个个数

=====================

[mysqld]

datadir=/var/lib/mysql

socket=/var/lib/mysql/mysql.sock

# Disabling symbolic-links is recommended to prevent assorted security risks

symbolic-links=0

# Settings user and group are ignored when systemd is used.

# If you need to run mysqld under a different user or group,

# customize your systemd unit file for mariadb according to the

# instructions in http://fedoraproject.org/wiki/Systemd

[mysqld_safe]

log-error=/var/log/mariadb/mariadb.log

pid-file=/var/run/mariadb/mariadb.pid

输出是这样的格式

[root@ansible test]# bash mysql_client.sh

1: mysqld 3

2: mysqld_safe 4

技术要点:

首先,过滤标题的信息,去掉左右的中括号

[root@ansible test]# sed -n '/\[*\]/p' my.cnf | sed -e 's/\[//g' -e 's/\]//g'

mysqld

mysqld_safe

[root@ansible test]#

其次,按照标题信息,取出每个标题之间的信息,过滤掉空行的数据,过滤掉注释的行数据,过滤掉标题行的数据,最终的实现是如下的样子

[root@ansible test]# sed -n '/\[mysqld\]/,/\[.*\]/p' my.cnf | grep -v "^$" | grep -v "#" | grep -v "\[.*\]"

datadir=/var/lib/mysql

socket=/var/lib/mysql/mysql.sock

symbolic-links=0

[root@ansible test]#

再次,对过滤完成的数据进行循环统计个数,最后组合成想要的数据就好了

 

实现代码如下:

[root@ansible test]# cat mysql_client.sh

#!/bin/bash

#

DIR_NAME=/etc/ansible/fang/test/my.cnf

function output_line

{

        echo "`sed -n '/\[.*\]/p' $DIR_NAME | sed -e 's/\[//g' -e 's/\]//g'`"

}

function output_line_items

{

        index=0

        items=`sed -n '/\['$1'\]/,/\[.*\]/p' $DIR_NAME | grep -v "^$" | grep -v "#" | grep -v "\[.*\]"`

        for item in $items

        do

           index=`expr $index + 1`

        done

        echo $index

}

number=0

for out in `output_line`

do

   number=`expr $number + 1`

   items_count=`output_line_items $out`

   echo "$number: $out $items_count"

done

[root@ansible test]#

删除操作,是不推荐的,因为匹配删除后,会继续进行下面的匹配,和预期结果是不一致的,匹配和行数颠倒以下,可以进行匹配,如下

Sed –i ‘/\/sbin\/nologin/,13d’ passwd 这种不推荐

Sed –i ‘13,/ \/sbin\/nologin /d’ passwd这种可以

 

练习题:

删除/etc/passwd中德尔第15行

sed –i ‘15d’ /etc/passwd

删除/etc/passwd中的第8行到第14行的所有内容

sed –i ‘8,14d’ /etc/passwd

删除/etc/passwd中的不能登录的用户(筛选条件: /sbin/nologin)

sed –i ‘/\/sbin\/nologin/d’ /etc/passwd

删除/etc/passwd中以mail开头的行,到以yarn开头的行的所有内容

sed –i ‘/^mail/,/^yarn/d’ /etc/passwd

删除/etc/passwd中以yarn开头的行到最后行的所有内容

sed –i ‘/^yarn/,$’ /etc/passwd

 

以#开头的注释删除掉,其中#号之前的空格也需要匹配[:blank:]表示空格

sed –i ‘/[:blank:]*#/d’ nginx.conf

在配置文件中所有不以#开头的行前面添加*符号,注意: 以#开头的行不添加

sed –i ‘s/[^#]/\*&/g’ nginx.cnf

sed语法(修改):

 

sed命令  匹配方式  /pattern1/s/old/new/

[root@ansible test]# sed -i '/socket=/s/socket/sockets/g' my.cnf

[root@ansible test]# cat my.cnf

[mysqld]

datadir=/var/lib/mysql

sockets=/var/lib/mysql/mysql.sock

练习题:

1、修改/etc/passwd中第1行中第1个root为ROOT  

      sed -i '1s/root/ROOT/' passwd

2、修改/etc/passwd中第5行到第10行中所有的/sbin/nologin为/bin/bash

      sed -i '5,10s/\/sbin\/nologin/\/bin\/bash/g' passwd

3、修改/etc/passwd中匹配到/sbin/nologin的行,将匹配到行中的login改为大写的LOGIN

      sed -i '/\/sbin\/nologin/s/login/LOGIN/g' passwd

4、修改/etc/passwd中从匹配到以root开头的行,到匹配到行中包含mail的所有行。修改内为将这些所有匹配到的行中的bin改为HADOOP

      sed -i '/^root/,/mail/s/bin/HADOOP/g' passwd

5、修改/etc/passwd中从匹配到以root开头的行,到第15行中的所有行,修改内容为将这些行中的nologin修改为SPARK

      sed -i '/^root/,15s/nologin/SPARK/g' passwd

6、修改/etc/passwd中从第15行开始,到匹配到以yarn开头的所有航,修改内容为将这些行中的bin换位BIN

      sed -i '15,/^yarn/s/bin/BIN/g' passwd

sed语法(修改)匹配的行后面追加

1、a     在匹配行后面追加         

2、i 在匹配行前面追加

3、r      将文件内容追加到匹配行后面

4、w    将匹配行写入指定文件

示例:

追加用法示例详解:

      1、a     append

(1)、passwd文件第10行后面追加"Add Line Behind"         

      sed -i '10a Add Line Begind' passwd

      (2)、passwd文件第10行到第20行,每一行后面都追加"Test Line Behind"

      sed -i '10,20a Test Line Behind' passwd

       (3)、passwd文件匹配到/bin/bash的行后面追加"Insert Line For /bin/bash Behind"

      sed -i '/\/bin\/bash/a Insert Line For /bin/bash Behind' passwd

2、i

(1)、passwd文件匹配到以yarn开头的行,在匹配航前面追加"Add Line Before"

      sed -i '/^yarn/i Add Line Before' passwd

           (2)、passwd文件每一行前面都追加"Insert Line Before Every Line"

      sed -i 'i Insert Line Before Every Line' passwd

      3、r

(1)、将/etc/fstab文件的内容追加到passwd文件的第20行后面

           sed -i '20r /etc/fstab' passwd

            (2)、将/etc/inittab文件内容追加到passwd文件匹配/bin/bash行的后面

           sed -i '/\/bin\/bash/r /etc/inittab' passwd

            (3)、将/etc/vconsole.conf文件内容追加到passwd文件中特定行后面,匹配以ftp开头的行,到第18行的所有行

           sed -i '//,18r /etc/vconsole.conf' passwd

4、w

       (1)、将passwd文件匹配到/bin/bash的行追加到/tmp/sed.txt文件中

           sed -i '/\/bin\/bash/w /tmp/sed.txt' passwd

            (2)、将passwd文件从第10行开始,到匹配到hdfs开头的所有行内容追加到/tmp/sed-1.txt

           sed -i '10,/^hdfs/w /tmp/sed-1.txt' passwd

匹配到行之前插入

Awk命令:

命令的格式:

Awk ‘BEGIN{}PATTERN{command}END{}’ file_name

语法格式               解释

BEGIN{}     正式处理数据之前执行

Pattern      匹配模式

{commands}  处理命令,可以多行

END{}     处理玩所有匹配数据后执行

内置变量:

      $0  打印行所有信息

      $1~$n   打印行的第1到n个字段的信息

      NF  Number Field     处理行的字段个数

      NR  Number Row     处理行的行号

      FNR      File Number Row多文件处理时,每个文件单独记录行号

      FS  Field Separator字段分割符,不指定时默认以空格或tab键分割

      RS  Row Separator   行分隔符,不指定时以回车分割\n

      OFS      Output Filed Separator  输出字段分隔符。

      ORS      Output Row Separator  输出行分隔符

      FILENAME   处理文件的文件名

      ARGC         命令行参数个数

      ARGV         命令行参数数组

例如:

输出每行的内容,默认是一个空格或者tab进行分割列

awk ‘{print $0}’ /etc/passwd

行分割   域分割   输出行分割符号

[root@ansible test]# cat 2.txt

xiaoli|xiaoming|xiaohua--fang|qi|ming--ni|shi|shui

[root@ansible test]#

[root@ansible test]# awk 'BEGIN{RS="--"}{print $0}END{}' 2.txt                

xiaoli|xiaoming|xiaohua

fang|qi|ming

ni|shi|shui

[root@ansible test]# awk 'BEGIN{RS="--";FS="|";OFS="&"}{print $3}END{}' 2.txt 

xiaohua

ming

shui

Printf格式化输出,参数介绍

awk格式化输出之printf总结:

      格式符

      %s       打印字符串

      %d       打印10进制数

      %f       打印浮点数

      %x       打印16进制数

      %o      打印8进制数

      %e       打印数字的科学计数法格式

      %c       打印单个字符的ASCII码

修饰符

      -          左对齐

      +         右对齐

      #         显示8进制在前面加0,显示16进制在前面加0x

格式符示例:

      1、以字符串格式打印/etc/passwd中的第7个字段,以":"作为分隔符

      awk 'BEGIN{FS=":"} {printf "%s",$7}' /etc/passwd

      2、以10进制格式打印/etc/passwd中的第3个字段,以":"作为分隔符

awk 'BEGIN{FS=":"} {printf "%d\n",$3}' /etc/passwd

      3、以浮点数格式打印/etc/passwd中的第3个字段,以":"作为分隔符

      awk 'BEGIN{FS=":"} {printf "%0.3f\n",$3}' /etc/passwd

4、以16进制数格式打印/etc/passwd中的第3个字段,以":"作为分隔符

      awk 'BEGIN{FS=":"} {printf "%#x\n",$3}' /etc/passwd

      5、以8进制数格式打印/etc/passwd中的第3个字段,以":"作为分隔符

      awk 'BEGIN{FS=":"} {printf "%#o\n",$3}' /etc/passwd

      6、以科学计数法格式打印/etc/passwd中的第3个字段,以":"作为分隔符

      awk 'BEGIN{FS=":"} {printf "%e\n",$3}' /etc/passwd

Awk模式匹配用法:

      第一种方法:RegExp

      第二种方法:运算符匹配

正则匹配RegExp

      匹配/etc/passwd文件行中含有root字符串的所有行

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

      匹配/etc/passwd文件行中以yarn开头的所有行

      awk 'BEGIN{FS=":"}/^yarn/{print $0}' /etc/passwd

运算符匹配

关系运算符匹配:

<               小于

>               大于

<=            小于等于

>=            大于等于

==            等于

!=              不等于

~               匹配正则表达式

!~              不匹配正则表达式

 (1)、以:为分隔符,匹配/etc/passwd文件中第3个字段小于50的所有行信息

awk 'BEGIN{FS=":"}$3<50{print $0}' /etc/passwd

 (2)、以:为分隔符,匹配/etc/passwd文件中第3个字段大于50的所有行信息

awk 'BEGIN{FS=":"}$3>50{print $0}' /etc/passwd

 (3)、以:为分隔符,匹配/etc/passwd文件中第7个字段为/bin/bash的所有行信息

awk 'BEGIN{FS=":"}$7=="/bin/bash"{print $0}' /etc/passwd

 (4)、以:为分隔符,匹配/etc/passwd文件中第7个字段不为/bin/bash的所有行信息

awk 'BEGIN{FS=":"}$7!="/bin/bash"{print $0}' /etc/passwd

 (5)、以:为分隔符,匹配/etc/passwd中第3个字段包含3个以上数字的所有行信息

awk 'BEGIN{FS=":"}$3~/[0-9]{3,}/{print $0}' /etc/passwd

 

布尔运算符匹配

||              或

&&             与

!                非

 (1)、以:为分隔符,匹配/etc/passwd文件中包含hdfs或yarn的所有行信息

awk 'BEGIN{FS=":"}$1=="hdfs" || $1=="yarn" {print $0}' /etc/passwd

 (2)、以:为分隔符,匹配/etc/passwd文件中第3个字段小于50并且第4个字段大于50的所有行信息

awk 'BEGIN{FS=":"}$3<50 && $4>50 {print $0}' /etc/passwd

awk动作中的表达式

+                    加

-                     减

*                     乘

/                     除

%                   取模

^或**              乘方

++x                      在返回x变量之前,x变量加1

x++                      在返回x变量之后,x变量加1

--x                   在返回x变量之前,x变量减1

x--                   在返回x变量之后,x变量减1

1、使用awk计算/etc/services中的空白行数量

awk '/^$/{sum++}END{print sum}' /etc/services

2、计算学生课程分数平均值,学生课程文件内容如下:

Alice  79   80    88   100

xiaoming 88 69   92    99

xiaoli      69   90  99    89

命令如下:

[root@ansible test]# cat student.txt

Alice  79   80    88   100

xiaoming 88 69   92    99

xiaoli      69   90  99    89

[root@ansible test]# awk 'BEGIN{printf "%-8s%-8s%-8s%-8s%-8s%-8s\n","Name","yuwen","math","pysical","English","Average"}{sum=$2+$3+$4+$5;AVG=sum/4;printf "%-8s%-8d%-8d%-8d%-8d%0.2f\n",$1,$2,$3,$4,$5,AVG}' student.txt

Name    yuwen   math    pysical English Average

Alice   79      80      88      100     86.75

xiaoming88      69      92      99      87.00

xiaoli  69      90      99      89      86.75

[root@ansible test]#

 

条件及循环语句

     

条件语句:

if(条件表达式1)

动作

else if(条件表达式2)

动作

else

动作

循环语句:

while循环:

while(条件表达式)

           动作

do while循环:

do

      动作

while(条件表达式)

for循环:

for(初始化计数器;计数器测试;计数器变更)

      动作

1、以:为分隔符,只打印/etc/passwd中第3个字段的数值在50-100范围内的行信息

代码:

[root@ansible test]# cat script.awk

BEGIN{

 FS=":"

}

{

if($3<50)

{

        printf "%-20s%-20s%10d\n","uid>50",$1,$3

}

else if($3>50 && $3<100)

{

        printf "%-20s%-20s%10d\n","100>uid>50",$1,$3

}

else

{

        printf "%-20s%-20s%10d\n","uid>100",$1,$3

}

}

[root@ansible test]# awk -f script.awk passwd

uid>50              root                         0

uid>50              bin                          1

uid>50              daemon                       2

uid>50              adm                          3

uid>50              lp                           4

练习: 使用do..while  while   for 来实现1+2+3….+100的和

字符串函数对照表

length(str)         计算长度

index(str1,str2)  返回在str1中查询到的str2的位置

tolower(str)       小写转换

toupper(str)      大写转换    

split(str,arr,fs)         分隔字符串,并保存到数组中

match(str,RE)          返回正则表达式匹配到的子串的位置

substr(str,m,n)  截取子串,从m个字符开始,截取n位。n若不指定,则默认截取到字符串尾

sub(RE,RepStr,str)   替换查找到的第一个子串,在str中搜索符合RE的字符串,将其替换为RepStr;只替换第一个

gsub(RE,RepStr,str)  替换查找到的所有子串,同上,区别替换所有

练习题:

字符串的长度

1、以:为分隔符,返回/etc/passwd中每行中每个字段的长度   

root:x:0:0:root:/root:/bin/bash

4:1:1:1:4:5:9

思考:利用到NF内置的变量,处理行的字段个数,每个遍历出来的字段利用函数算出长度打印输出

代码:

[root@ansible test]# cat test.awk

BEGIN{

FS=":"

}

{

i=1

while(i<=NF)

{

 if(i==NF)

    printf "%d",length($i)

 else

    printf "%d:",length($i)

i++

}

printf "\n"

}

[root@ansible test]# awk -f test.awk passwd1

4:1:0:0:4:5:9

17

3:1:0:0:3:4:13

6:1:0:0:6:5:13

匹配字符串的位置

搜索字符串"I have a dream"中出现"ea"子串的位置

[root@ansible test]# awk 'BEGIN{string="I hava a dream";aa=match(string,"ea");print aa}'

12

大小写转换

[root@ansible test]# awk 'BEGIN{str="i Want you";print toupper(str);print tolower(str)}'

I WANT YOU

i want you

子字符串的获取

[root@ansible test]# awk 'BEGIN{str="my name is fangqiming";print substr(str,12,19)}'

Fangqiming

字符串的分割

[root@ansible test]# awk 'BEGIN{str="My Name Is FangQiMing";split(str,arr," ");print arr[4]}'

FangQiMing

字符串的替换

[root@ansible test]# awk 'BEGIN{str="My Name Is FangQiMing1988 [email protected]";print gsub(/[0-9]+/,"@secret@",str);print str}'

2

My Name Is FangQiMing@secret@ @secret@@qq.com

[root@ansible test]#

Awk选项总结:

awk中常用选项

-v         定义或引用变量

-f         指定awk命令文件

-F         指定分隔符

-V        查看awk的版本号

 

[root@ansible test]# awk -v var=$var1 -v ages=$age 'BEGIN{print var,ages}'

fangqiming 32

[root@ansible test]#

指定分隔符

[root@ansible test]# awk -F: '{print $7}' passwd

[root@ansible test]# awk 'BEGIN{FS=":"}{print $7}' passwd

以上两种方式作用相同

[root@ansible test]# awk -V

GNU Awk 4.0.2

数组的使用:

Shell中数组的用法:

array=("Allen" "Mike" "Messi" "Jerry" "Hanmeimei" "Wang")

打印元素:             echo ${array[2]}

打印元素个数:         echo ${#array[@]}

打印元素长度:       echo ${#array[3]}

给元素赋值:          array[3]="Li"

删除元素:             unset array[2];unset array

分片访问:             echo ${array[@]:1:3}

元素内容替换:       ${array[@]/e/E} 只替换第一个e;${array[@]//e/E}替换所有的e

数组的遍历:

for a in ${array[@]}

do

      echo $a

done

示例如下:

[root@ansible test]# arr=("xiaoli" "hanmeimemi" "lilei" "fang" "zhang")

[root@ansible test]# echo $arr

xiaoli

[root@ansible test]# echo ${arr[@]}

xiaoli hanmeimemi lilei fang zhang

[root@ansible test]# unset arr[0]

[root@ansible test]# echo ${arr[@]}

hanmeimemi lilei fang zhang

[root@ansible test]# for i in ${arr[@]}; do echo $i; done

hanmeimemi

lilei

fang

zhang

[root@ansible test]#

Awk中数组的用法:

在awk中,使用数组时,不仅可以使用1.2..n作为数组下标,也可以使用字符串作为数组下标

     

当使用1.2.3..n时,直接使用array[2]访问元素;需要遍历数组时,使用以下形式:

str="Allen Jerry Mike Tracy Jordan Kobe Garnet"

split(str,array)

for(i=1;i<=length(array);i++)

print array[i]

当使用字符串作为数组下标时,需要使用array[str]形式访问元素;遍历数组时,使用以下形式:

array["var1"]="Jin"

array["var2"]="Hao"

array["var3"]="Fang"

for(a in array)

      print array[a]

数组是以数字为下标的情况,默认是从1开始的

[root@ansible test]# awk 'BEGIN{arr="xiaoli xiaoming fang";split(arr,array1);for(i=1;i<=length(array1);i++) print array1[i]}'

xiaoli

xiaoming

fang

[root@ansible test]#

数组下标以字符串为标示的情况下使用

[root@ansible test]# awk 'BEGIN{array1["num1"]="xiaoli";array1["num2"]="fang";for(arr in array1) print array1[arr]}'

xiaoli

fang

[root@ansible test]#

练习题:

1、统计主机上所有的TCP连接状态数,按照每个TCP状态分类

netstat -an | grep tcp | awk '{array[$6]++}END{for(a in array) print a,array[a]}'

                

2、计算横向数据总和,计算纵向数据总和

allen     80  90  87  91  348

mike     78  86  93  96  256

Kobe    66  92  82  78  232

Jerry     98  74  66  54  356

Wang    87  21  100 43  322

234   342   451   456   342

  1. 确保系统中有httpd

Rpm –ql httpd

[root@ansible test]# netstat -an | grep tcp #查看tcp的监听情况

[root@ansible test]# netstat -an | grep tcp | awk '{print $6}'#查看tcp监听端口的第六个元素

Awk统计命令如下

[root@ansible test]# netstat -an | grep tcp | awk 'BEGIN{}{array1[$6]++}END{for( arr in array1) print arr,array1[arr]}'

LISTEN 13

ESTABLISHED 1

[root@ansible test]#

  1. 计算横向数据总和,计算纵向数据总和

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章