• Linux 管道


    管道命令

    “ | ”,竖线符号代表的就是管道符
    管道是一种两个进程间进行单向通信的机制。因为管道传递数据的单向性,所以又称为半双工管道。
    介绍:

    • 管道可以根据一组命令按照数据流向的方式来进行操作。简单的说,第一个命令执行后,不回显结果,而是把结果通过管道传递给第二个命令,第二个命令处理后再传给第三个….直到没有管道符后才终止命令,并回显最终结果。
    • 管道可以把不同的命令组合成强大的指令集合。比如,对文件夹下所有的txt结尾的文件重命名,就需要三个管道符号,四个命令完成。

    缺点:

    1. 数据只能从一个进程流向另一个进程(其中一个读管道,一个写管道)。如果要进行双工通信,需要建立两个管道。
    2. 管道只能用于父子进程或兄弟进程间通信,也就是说管道只能用于具有亲缘关系的进程间通信。
    3. 管道所传输的是无格式的字节流。

    通过管道通信的两个进程,一个进程向管道写数据,另一个从中读数据。写入的数据每次都添加到管道缓冲区的末尾,读数据的时候都是冲缓冲区的头部读出数据的。

    利用管道查看/root/install.log文件的内容并分页显示

    [root@ylg ~]# cat install.log | more
    

    对于常用的可以直接用于管道的命令,主要有:

    • cut  用来显示行中的指定部分,删除文件中指定字段。

    • grep  grep(global search regular expression(RE) and print out the line,全面搜索正则表达式并把行打印出来)是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来。

    • sort 用于将文本文件内容加以排序。sort可针对文本文件的内容,以行为单位来排序。

    • uniq  用于报告或忽略文件中的重复行,一般与sort命令结合使用。

    • wc  用来计算数字。利用wc指令我们可以计算文件的Byte数、字数或是列数,若不指定文件名称,或是所给予的文件名为“-”,则wc指令会从标准输入设备读取数据。 

    • tee  用于读取标准输入的数据,并将其内容输出成文件。tee指令会从标准输入设备读取数据,将其内容输出到标准输出设备,同时保存成文件。

      • tee [-ai][--help][--version][文件...]
        
        -a或--append  附加到既有文件的后面,而非覆盖它.
        -i或--ignore-interrupts  忽略中断信号。
        
    • tr 可以对来自标准输入的字符进行替换、压缩和删除。它可以将一组字符变成另一组字符,经常用来编写优美的单行命令,作用很强大。

    • col  用于过滤控制字符。在许多UNIX说明文件里,都有RLF控制字符。当我们运用shell特殊字符">"和">>",把说明文件的内容输出成纯文本文件时,控制字符会变成乱码,col指令则能有效滤除这些控制字符。

    • join  用于将两个文件中,指定栏位内容相同的行连接起来。找出两个文件中,指定栏位内容相同的行,并加以合并,再输出到标准输出设备。

    • paste  paste命令用于合并文件的列。paste指令会把每个文件以列对列的方式,一列列地加以合并。和join命令类似。

      • paste [-s][-d <间隔字符>][--help][--version][文件...]
        -d<间隔字符>或--delimiters=<间隔字符>  用指定的间隔字符取代跳格字符。
        -s或--serial  串列进行而非平行处理。
        
    • expand   用于将文件的制表符(TAB)转换为空白字符(space),将结果显示到标准输出设备。

    • xargs

    cut

    语法

    cut  [-bn] [file]
    cut [-c] [file]
    cut [-df] [file]
    

    使用说明:

    cut 命令从文件的每一行剪切字节、字符和字段并将这些字节、字符和字段写至标准输出。

    如果不指定 File 参数,cut 命令将读取标准输入。必须指定 -b、-c 或 -f 标志之一。

    参数

    对象 说明
    -b 仅显示行中指定直接范围的内容;
    -c 仅显示行中指定范围的字符;
    -d 指定字段的分隔符,默认的字段分隔符为“TAB”;
    -f 显示指定字段的内容;
    -n 与“-b”选项连用,不分割多字节字符;
    --complement 补足被选择的字节、字符或字段;
    --out-delimiter=<字段分隔符> 指定输出内容是的字段分割符;
    --help 显示指令的帮助信息;
    --version 显示指令的版本信息。

    指定字段的字符或者字节范围

    cut命令可以将一串字符作为列来显示,字符字段的记法:

    • N-:从第N个字节、字符、字段到结尾;
    • N-M:从第N个字节、字符、字段到第M个(包括M在内)字节、字符、字段;
    • -M:从第1个字节、字符、字段到第M个(包括M在内)字节、字符、字段。

    上面是记法,结合下面选项将摸个范围的字节、字符指定为字段:

    • -b 表示字节;
    • -c 表示字符;
    • -f 表示定义字段。

    实例

    [root@localhost text]# cat test.txt 
    abcdefghijklmnopqrstuvwxyz
    abcdefghijklmnopqrstuvwxyz
    abcdefghijklmnopqrstuvwxyz
    abcdefghijklmnopqrstuvwxyz
    abcdefghijklmnopqrstuvwxyz
    

    打印第1个到第3个字符:

    [root@localhost text]# cut -c1-3 test.txt 
    abc
    abc
    abc
    abc
    abc
    

    打印前2个字符:

    [root@localhost text]# cut -c-2 test.txt 
    ab
    ab
    ab
    ab
    ab
    

    打印从第5个字符开始到结尾:

    [root@localhost text]# cut -c5- test.txt 
    efghijklmnopqrstuvwxyz
    efghijklmnopqrstuvwxyz
    efghijklmnopqrstuvwxyz
    efghijklmnopqrstuvwxyz
    efghijklmnopqrstuvwxyz
    

    grep

    grep(global search regular expression(RE) and print out the line,全面搜索正则表达式并把行打印出来)是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹配的行打印出来。

    语法

    grep [-abcEFGhHilLnqrsvVwxy][-A<显示列数>][-B<显示列数>][-C<显示列数>][-d<进行动作>][-e<范本样式>][-f<范本文件>][--help][范本样式][文件或目录...]
    

    选项

    对象 说明
    -a或--text 不要忽略二进制的数据。
    -A<显示列数>或--after-context=<显示列数> 除了显示符合范本样式的那一列之外,并显示该列之后的内容。
    -b或--byte-offset 在显示符合范本样式的那一列之前,标示出该列第一个字符的位编号。
    -B<显示列数>或--before-context=<显示列数> 除了显示符合范本样式的那一列之外,并显示该列之前的内容。
    -c或--count 计算符合范本样式的列数。
    -C<显示列数>或--context=<显示列数>或-<显示列数> 除了显示符合范本样式的那一列之外,并显示该列之前后的内容。
    -d<进行动作>或--directories=<进行动作> 当指定要查找的是目录而非文件时,必须使用这项参数,否则grep指令将回报信息并停止动作。
    -e<范本样式>或--regexp=<范本样式> 指定字符串做为查找文件内容的范本样式。
    -E或--extended-regexp 将范本样式为延伸的普通表示法来使用。
    -f<范本文件>或--file=<范本文件> 指定范本文件,其内容含有一个或多个范本样式,让grep查找符合范本条件的文件内容,格式为每列一个范本样式。
    -F或--fixed-regexp 将范本样式视为固定字符串的列表。
    -G或--basic-regexp 将范本样式视为普通的表示法来使用。
    -h或--no-filename 在显示符合范本样式的那一列之前,不标示该列所属的文件名称。
    -H或--with-filename 在显示符合范本样式的那一列之前,表示该列所属的文件名称。
    -i或--ignore-case 忽略字符大小写的差别。
    -l或--file-with-matches 列出文件内容符合指定的范本样式的文件名称。
    -L或--files-without-match 列出文件内容不符合指定的范本样式的文件名称。
    -n或--line-number 在显示符合范本样式的那一列之前,标示出该列的列数编号。
    -q或--quiet或--silent 不显示任何信息。
    -r或--recursive 此参数的效果和指定"-d
    -s或--no-messages 不显示错误信息。
    -v或--revert-match 反转查找。
    -V或--version 显示版本信息。
    -w或--word-regexp 只显示全字符合的列。
    -x或--line-regexp 只显示全列符合的列。
    -y 此参数的效果和指定"-i"参数相同。
    --help 在线帮助。

    实例

    实例

    1、在当前目录中,查找后缀有 file 字样的文件中包含 test 字符串的文件,并打印出该字符串的行。此时,可以使用如下命令:

    grep test *file 
    

    结果如下所示:

    $ grep test test* #查找后缀有“test”的文件包含“test”字符串的文件  
    testfile1:This a Linux testfile! #列出testfile1 文件中包含test字符的行  
    testfile_2:This is a linux testfile! #列出testfile_2 文件中包含test字符的行  
    testfile_2:Linux test #列出testfile_2 文件中包含test字符的行 
    

    2、以递归的方式查找符合条件的文件。例如,查找指定目录/etc/acpi 及其子目录(如果存在子目录的话)下所有文件中包含字符串"update"的文件,并打印出该字符串所在行的内容,使用的命令为:

    grep -r update /etc/acpi 
    

    输出结果如下:

    $ grep -r update /etc/acpi #以递归的方式查找“etc/acpi”  
    #下包含“update”的文件  
    /etc/acpi/ac.d/85-anacron.sh:# (Things like the slocate updatedb cause a lot of IO.)  
    Rather than  
    /etc/acpi/resume.d/85-anacron.sh:# (Things like the slocate updatedb cause a lot of  
    IO.) Rather than  
    /etc/acpi/events/thinkpad-cmos:action=/usr/sbin/thinkpad-keys--update 
    

    3、反向查找。前面各个例子是查找并打印出符合条件的行,通过"-v"参数可以打印出不符合条件行的内容。

    查找文件名中包含 test 的文件中不包含test 的行,此时,使用的命令为:

    grep -v test *test*
    

    结果如下所示:

    $ grep-v test* #查找文件名中包含test 的文件中不包含test 的行  
    testfile1:helLinux!  
    testfile1:Linis a free Unix-type operating system.  
    testfile1:Lin  
    testfile_1:HELLO LINUX!  
    testfile_1:LINUX IS A FREE UNIX-TYPE OPTERATING SYSTEM.  
    testfile_1:THIS IS A LINUX TESTFILE!  
    testfile_2:HELLO LINUX!  
    testfile_2:Linux is a free unix-type opterating system.
    

    4、打印出匹配文本之前或者之后的行

    #显示匹配某个结果之后的3行,使用 -A 选项:
    seq 10 | grep "5" -A 3
    5
    6
    7
    8
    
    #显示匹配某个结果之前的3行,使用 -B 选项:
    seq 10 | grep "5" -B 3
    2
    3
    4
    5
    
    #显示匹配某个结果的前三行和后三行,使用 -C 选项:
    seq 10 | grep "5" -C 3
    2
    3
    4
    5
    6
    7
    8
    
    #如果匹配结果有多个,会用“--”作为各匹配结果之间的分隔符:
    echo -e "a
    b
    c
    a
    b
    c" | grep a -A 1
    a
    b
    --
    a
    b
    

    sort

    Linux sort命令用于将文本文件内容加以排序。sort可针对文本文件的内容,以行为单位来排序。

    语法

    sort [-bcdfimMnr][-o<输出文件>][-t<分隔字符>][+<起始栏位>-<结束栏位>][--help][--verison][文件]
    

    选项

    对象 说明
    -b 忽略每行前面开始出的空格字符。
    -c 检查文件是否已经按照顺序排序。
    -d 排序时,处理英文字母、数字及空格字符外,忽略其他的字符。
    -f 排序时,将小写字母视为大写字母。
    -i 排序时,除了040至176之间的ASCII字符外,忽略其他的字符。
    -m 将几个排序好的文件进行合并。
    -M 将前面3个字母依照月份的缩写进行排序。
    -n 依照数值的大小排序。
    -o<输出文件> 将排序后的结果存入指定的文件。
    -r 以相反的顺序来排序。
    -t<分隔字符> 指定排序时所用的栏位分隔字符。
    +<起始栏位>-<结束栏位> 以指定的栏位来排序,范围由起始栏位到结束栏位的前一栏位。
    --help 显示帮助。
    --version 显示版本信息。

    -k选项的具体语法格式:

    -k选项的语法格式:

    FStart.CStart Modifie,FEnd.CEnd Modifier
    -------Start--------,-------End--------
     FStart.CStart 选项  ,  FEnd.CEnd 选项
    
    

       这个语法格式可以被其中的逗号,分为两大部分,Start部分和End部分。Start部分也由三部分组成,其中的Modifier部分就是我们之前说过的类似n和r的选项部分。我们重点说说Start部分的FStartC.StartC.Start也是可以省略的,省略的话就表示从本域的开头部分开始。FStart.CStart,其中FStart就是表示使用的域,而CStart则表示在FStart域中从第几个字符开始算“排序首字符”。同理,在End部分中,你可以设定FEnd.CEnd,如果你省略.CEnd,则表示结尾到“域尾”,即本域的最后一个字符。或者,如果你将CEnd设定为0(零),也是表示结尾到“域尾”。

    从公司英文名称的第二个字母开始进行排序:

    $ sort -t ' ' -k 1.2 facebook.txt
    baidu 100 5000
    sohu 100 4500
    google 110 5000
    guge 50 3000
    
    

      使用了-k 1.2,表示对第一个域的第二个字符开始到本域的最后一个字符为止的字符串进行排序。你会发现baidu因为第二个字母是a而名列榜首。sohu和 google第二个字符都是o,但sohu的h在google的o前面,所以两者分别排在第二和第三。guge只能屈居第四了。

    只针对公司英文名称的第二个字母进行排序,如果相同的按照员工工资进行降序排序:

    $ sort -t ' ' -k 1.2,1.2 -nrk 3,3 facebook.txt
    baidu 100 5000
    google 110 5000
    sohu 100 4500
    guge 50 3000
    
    

      由于只对第二个字母进行排序,所以我们使用了-k 1.2,1.2的表示方式,表示我们“只”对第二个字母进行排序。(如果你问“我使用-k 1.2怎么不行?”,当然不行,因为你省略了End部分,这就意味着你将对从第二个字母起到本域最后一个字符为止的字符串进行排序)。对于员工工资进行排 序,我们也使用了-k 3,3,这是最准确的表述,表示我们“只”对本域进行排序,因为如果你省略了后面的3,就变成了我们“对第3个域开始到最后一个域位置的内容进行排序” 了。

    uniq

    Linux uniq命令用于检查及删除文本文件中重复出现的行列。

    uniq可检查文本文件中重复出现的行列。

    语法

    uniq [-cdu][-f<栏位>][-s<字符位置>][-w<字符位置>][--help][--version][输入文件][输出文件]
    

    选项

    对象 说明
    -c或--count 在每列旁边显示该行重复出现的次数。
    -d或--repeated 仅显示重复出现的行列。
    -f<栏位>或--skip-fields=<栏位> 忽略比较指定的栏位。
    -s<字符位置>或--skip-chars=<字符位置> 忽略比较指定的字符。
    -u或--unique 仅显示出一次的行列。
    -w<字符位置>或--check-chars=<字符位置> 指定要比较的字符。
    --help 显示帮助。
    --version 显示版本信息。

    wc

    语法

    wc [-clw][--help][--version][文件...]
    

    选项

    对象 说明
    -c或--bytes或--chars 只显示Bytes数。
    -l或--lines 只显示行数。
    -w或--words 只显示字数。

    tr

    tr 指令从标准输入设备读取数据,经过字符串转译后,将结果输出到标准输出设备。

    语法

    tr [-cdst][--help][--version][第一字符集][第二字符集]  
    tr [OPTION]…SET1[SET2]
    

    选项

    对象 说明
    -c, --complement 反选设定字符。也就是符合 SET1 的部份不做处理,不符合的剩余部份才进行转换
    -d, --delete 删除指令字符
    -s, --squeeze-repeats 缩减连续重复的字符成指定的单个字符
    -t, --truncate-set1 削减 SET1 指定范围,使之与 SET2 设定长度相等

    字符集合的范围:

    字符 说明 字符 说明
    NNN 八进制值的字符 NNN (1 to 3 为八进制值的字符) \ 反斜杠
    a Ctrl-G 铃声  Ctrl-H 退格符
    f Ctrl-L 走行换页 Ctrl-J 新行
    Ctrl-M 回车 Ctrl-I tab键
    v Ctrl-X 水平制表符
    CHAR1-CHAR2 字符范围从 CHAR1 到 CHAR2 的指定,范围的指定以 ASCII 码的次序为基础,只能由小到大,不能由大到小。 [CHAR*] 这是 SET2 专用的设定,功能是重复指定的字符到与 SET1 相同长度为止
    [CHAR*REPEAT] 这也是 SET2 专用的设定,功能是重复指定的字符到设定的 REPEAT 次数为止(REPEAT 的数字采 8 进位制计算,以 0 为开始) [:alnum:] 所有字母字符与数字
    [:alpha:] 所有字母字符 [:blank:] 所有水平空格
    [:cntrl:] 所有控制字符 [:digit:] 所有数字
    [:graph:] 所有可打印的字符(不包含空格符) [:lower:] 所有小写字母
    [:print:] 所有可打印的字符(包含空格符) [:punct:] 所有标点字符
    [:space:] 所有水平与垂直空格符 [:upper:] 所有大写字母
    [:xdigit:] 所有 16 进位制的数字 [=CHAR=] 所有符合指定的字符(等号里的 CHAR,代表你可自订的字符)

    join

    Linux join命令用于将两个文件中,指定栏位内容相同的行连接起来。

    找出两个文件中,指定栏位内容相同的行,并加以合并,再输出到标准输出设备。

    语法

    join [-i][-a<1或2>][-e<字符串>][-o<格式>][-t<字符>][-v<1或2>][-1<栏位>][-2<栏位>][--help][--version][文件1][文件2]
    

    选项

    对象 说明
    -a<1或2> 除了显示原来的输出内容之外,还显示指令文件中没有相同栏位的行。
    -e<字符串> 若[文件1]与[文件2]中找不到指定的栏位,则在输出中填入选项中的字符串。
    -i或--igore-case 比较栏位内容时,忽略大小写的差异。
    -o<格式> 按照指定的格式来显示结果。
    -t<字符> 使用栏位的分隔字符。
    -v<1或2> 跟-a相同,但是只显示文件中没有相同栏位的行。
    -1<栏位> 连接[文件1]指定的栏位。
    -2<栏位> 连接[文件2]指定的栏位。

    实例

    连接两个文件。

    为了清楚地了解join命令,首先通过cat命令显示文件testfile_1和 testfile_2 的内容。

    然后以默认的方式比较两个文件,将两个文件中指定字段的内容相同的行连接起来,在终端中输入命令:

    join testfile_1 testfile_2 
    

    首先查看testfile_1、testfile_2 中的文件内容:

    $ cat testfile_1 #testfile_1文件中的内容  
    Hello 95 #例如,本例中第一列为姓名,第二列为数额  
    Linux 85  
    test 30  
    ~$ cat testfile_2 #testfile_2文件中的内容  
    Hello 2005 #例如,本例中第一列为姓名,第二列为年份  
    Linux 2009  
    test 2006 
    

    然后使用join命令,将两个文件连接,结果如下:

    $ join testfile_1 testfile_2 #连接testfile_1、testfile_2中的内容  
    Hello 95 2005 #连接后显示的内容  
    Linux 85 2009  
    test 30 2006 
    

    文件1与文件2的位置对输出到标准输出的结果是有影响的。

    xargs

      xargs命令是给其他命令传递参数的一个过滤器,也是组合多个命令的一个工具。它擅长将标准输入数据转换成命令行参数,xargs能够处理管道或者stdin并将其转换成特定命令的命令参数。xargs也可以将单行或多行文本输入转换为其他格式,例如多行变单行,单行变多行。xargs的默认命令是echo,空格是默认定界符。这意味着通过管道传递给xargs的输入将会包含换行和空白,不过通过xargs的处理,换行和空白将被空格取代。xargs是构建单行命令的重要组件之一。

    语法

    xargs [ -p ] [ -t] [ -e[ EOFString ] ] [ -EEOFString ] [ -i[ ReplaceString ] ] [ -IReplaceString ] [ -l [ Number ] ] [ -L Number ] [ -n Number [ -x ] ] [ -s Size ] [ Command [ Argument ... ] ]
    

    选项

    对象 说明
    -0 如果输入的stdin含有特殊字符,例如反引号`、反斜杠、空格等字符时,xargs可以将它还原成一般字符。为xargs的默认选项。
    -e 、<flag>,-E <flag>,--eof=<eof-str> eof是end of file string的意思。flag可以是一个字符串或者是由空格分隔的多个字符串,当xargs分析到这个flag时,就会停止工作。
    -p 当每次执行一个argument的时候询问一次用户。
    -n <num> 表示命令在执行的时候一次使用的argument的个数,由num指定,默认是用所有的参数。
    -t 表示先打印命令,然后再执行。
    -a <file> 从文件中读入作为sdtin。
    -i,-I 其中-I某些Linux版本不支持。将xargs的输出每一项参数,单独赋值给后面的命令,参数需要用{}代替。见示例3。
    -r 或者--no-run-if-empty,当xargs的输入为空的时候则停止xargs,不用再去执行后面的命令了,-r是xargs的默认选项。
    -s <num> 命令行的最大字符数,指的是xargs后面那个命令的最大命令行字符数,包括命令、空格和换行符。每个参数单独传入xargs后面的命令。
    -L <line_num> 设置标准输入中最大的行数作为命令每一次执行的参数。
    -d <delim>, --delimiter=<delim> xargs处理标准输入默认是按换行符和空格作为分隔符,输出arguments的分隔符是空格,这里修改xargs处理标准输入时的分隔符。
    -x eXit的意思,主要是配合-s使用,当命令行字符数大于-s指定的数值时,退出xargs。
    -P 修改最大的进程数,默认是1,为0时候为as many as it can。该选项比较少用,目前还不清楚该用法。

    实例

    xargs用作替换工具,读取输入数据重新格式化后输出。

    定义一个测试文件,内有多行文本数据:

    cat test.txt
    
    a b c d e f g
    h i j k l m n
    o p q
    r s t
    u v w x y z
    

    多行输入单行输出:

    cat test.txt | xargs
    
    a b c d e f g h i j k l m n o p q r s t u v w x y z
    

    -n选项多行输出:

    cat test.txt | xargs -n3
    
    a b c
    d e f
    g h i
    ......
    

    -d选项可以自定义一个定界符:

    echo "nameXnameXnameXname" | xargs -dX
    
    name name name name
    

    结合-n选项使用:

    echo "nameXnameXnameXname" | xargs -dX -n2
    
    name name
    name name
    

    读取stdin,将格式化后的参数传递给命令

    假设一个命令为 sk.sh 和一个保存参数的文件arg.txt:

    #!/bin/bash
    #sk.sh命令内容,打印出所有参数。
    
    echo $*
    
    

    arg.txt文件内容:

    cat arg.txt
    
    aaa
    bbb
    ccc
    
    

    xargs的一个选项-I,使用-I指定一个替换字符串{},这个字符串在xargs扩展时会被替换掉,当-I与xargs结合使用,每一个参数命令都会被执行一次:

    cat arg.txt | xargs -I {} ./sk.sh -p {} -l
    
    -p aaa -l
    -p bbb -l
    -p ccc -l
    
    

    复制所有图片文件到 /data/images 目录下:

    ls *.jpg | xargs -n1 -I cp {} /data/images
    

    xargs结合find使用

    用rm 删除太多的文件时候,可能得到一个错误信息:/bin/rm Argument list too long. 用xargs去避免这个问题:

    find . -type f -name "*.log" -print0 | xargs -0 rm -f
    

    xargs -0将作为定界符。

    统计一个源代码目录中所有php文件的行数:

    find . -type f -name "*.php" -print0 | xargs -0 wc -l
    

    查找所有的jpg 文件,并且压缩它们:

    find . -type f -name "*.jpg" -print | xargs tar -czvf images.tar.gz
    
    

    xargs其他应用

    假如你有一个文件包含了很多你希望下载的URL,你能够使用xargs下载所有链接:

    cat url-list.txt | xargs wget -c
    
  • 相关阅读:
    AJAX异步传输——以php文件传输为例
    js控制json生成菜单——自制菜单(一)
    vs2010中关于HTML控件与服务器控件分别和js函数混合使用的问题
    SQL数据库连接到服务器出错——无法连接到XXX
    PHP错误:Namespace declaration statement has to be the very first statement in the script
    【LeetCode】19. Remove Nth Node From End of List
    【LeetCode】14. Longest Common Prefix
    【LeetCode】38. Count and Say
    【LeetCode】242. Valid Anagram
    【LeetCode】387. First Unique Character in a String
  • 原文地址:https://www.cnblogs.com/yangliguo/p/8463080.html
Copyright © 2020-2023  润新知