加密日志
这篇日志被加密了。请输入密码后查看。
密码
问题:service memcached31211 start 有输出,加上 2>&1就没有输出了,
combine stderr and stdout into the stdout stream,2>&1的意思是将错误输出和标准输出都放前面文件里面:
Starting memcached31211 ...                                [  OK  ]
[ init.d]# vi memcached31211

参考自:https://www.cnblogs.com/happySmily/p/6439959.html

启动文件/etc/init.d/memcached31211下载:


背景:memcache线上环境出现端口还在,但是执行命令就一直柱塞的情况,怎么办?只有打开日志了。运维觉得是:像是进程死了,技术觉得是读写多了,无证据只能是大胆的猜测,得找证据,从下次崩溃的日志里找,呵呵。
memcache在linux上安装时并不支持显示地配置服务日志,我们如果想要把memcache服务日志保存到日志文件中,则需要在启动参数中进行配置。
安装好memcache后,我们可以通过-h命令查看memcached支持的参数:
/usr/local/bin/memcached -h
-v            verbose (print errors/warnings while in event loop)
-vv           very verbose (also print client commands/reponses)

建议在启动memcached时加上日志,
出问题时候从日志上找到蛛丝马迹,
出问题后立即ps看其进程处啥状态:
-vv >> /tmp/memcached.log 2>&1  


加个日志吧,日志注意下到时间清理下:
/usr/local/bin/memcached -d -m 5120  -u root -l  10.70.62.*** -p 11211 -c 2048 -u root -vv >> /tmp/memcached.log 2>&1  
-v            verbose (print errors/warnings while in event loop)
-vv           very verbose (also print client commands/reponses)

从上面可以看到,启动memcached时有3个参数是和日志信息相关的:
其中-v代表打印普通的错误或者警告类型的日志信息
-vv比-v打印的日志更详细,包含了客户端命令和server端的响应信息
-vvv则是最详尽的,甚至包含了内部的状态信息打印

你可以根据你的实际需要来选择对应的参数,我这里使用-vv就OK了。
由于我们需要把日志信息保存在文件中,而不是在控制台输出,而-vv等参数只能把日志信息输出在控制台。所以我们需要对-vv参数的输出进行数据流重定向,关于重定向的知识在这里就不细述了,有兴趣的可以查下资料了解一下。
综上,启动memcached的命令如下:

Shell代码  收藏代码
/usr/local/memcached/bin/memcached -d -m 2048 -p $1 -u root -vv >> /tmp/memcached.log 2>&1  
重点在最后的:-vv >> /tmp/memcached.log 2>&1

-vv >> /tmp/memcached.log:代表把-vv的输出重定向到/tmp/memcached.log 文件中
2>&1的意思是把错误日志也一起写入到该文件中

启动成功后我们可以测试一下,首先起两个terminal,terminal1用来查看日志信息,terminal2进行client操作
terminal1:启动memcached后默认的日志信息如下
Shell代码  收藏代码
[chenzhou@localhost ~]$ tail -f /tmp/memcached.log  
<31 send buffer was 110592, now 268435456  
<30 server listening (udp)  
<31 server listening (udp)  
<30 server listening (udp)  
<31 server listening (udp)  
<30 server listening (udp)  
<30 server listening (udp)  
<31 server listening (udp)  
<31 server listening (udp)  
<32 new auto-negotiating client connection  
terminal2:往memcached里存入一个数据
Shell代码  收藏代码
[root@localhost bin]# telnet localhost 11211  
Trying 127.0.0.1...  
Connected to localhost.localdomain (127.0.0.1).  
Escape character is '^]'.  
set name 0 60 5 chenzhou  
如上所示:使用set命令存入key为name value为chenzhou
terminal1日志记录:
Shell代码  收藏代码
32: Client using the ascii protocol  
<32 set name 0 60 5 chenzhou  
这样,我们的配置就生效了。

摘自:http://chenzhou123520.iteye.com/blog/1925209
背景:有人对vim+ctag有意见,于是有人就说这个玩意好了。

YouCompleteMe的特别之处
基于语义补全

  总所周知,Vim是一款文本编辑器。也就是说,其最基础的工作就是编辑文本,而不管该文本的内容是什么。在Vim被程序员所使用后,其慢慢的被肩负了与IDE一样的工作,文本自动补全(ie.acp,omnicppcompleter),代码检查(Syntastic)等等工作。

  针对文本自动补全这个功能来说,主要有两种实现方式。

    基于文本

  我们常用的omnicppcompleter,acp,vim自带的c-x, c-n的实现方式就是基于文本。更通俗的说法,其实就是一个字:


  其通过文本进行一些正则表达式的匹配,再根据生成的tags(利用ctags生成)来实现自动补全的效果。

    基于语义

  顾名思义,其是通过分析源文件,经过语法分析以后进行补全。由于对源文件进行分析,基于语义的补全可以做到很精确。但是这显然是vim所不可能支持的。而且经过这么多年发展,由于语法分析有很高的难度,也一直没有合适的工具出现。直到,由apple支持的clang/llvm横空出世。YouCompleteMe也正是在clang/llvm的基础上进行构建的。
整合实现了多种插件

    clang_complete
    AutoComplPop
    Supertab
    neocomplcache
    Syntastic(类似功能,仅仅针对c/c++/obj-c代码)

支持语言

    c
    c++
    obj-c
    c#
    python

  对于其他的语言,会调用vim设置的omnifunc来匹配,因此同样支持php,ruby等语言。

http://jishu.zol.com.cn/228882.html
背景:主要是遇到编译时要函数返回一个void *,否则会提示:warning: no return statement in function returning non-void,如果去掉这个线程函数的void *里的星号会报错: invalid conversion from ‘void (*)(void*)’ to ‘void* (*)(void*)’ 。

pthread注意事项

注意,pthread_create第三个参数,也就是线程回调函数格式为:
void* fnThreadFun(void* param)
{
  return NULL;//或return ((void *)0);
}
其返回值为void*型指针,如果写成void fnThreadFun(void* param)形式,那么编译会报告:
error: invalid conversion from ‘void (*)(void*)’ to ‘void* (*)(void*)’ [-fpermissive]
错误。
写成:
err = pthread_create(&ntid,NULL,(void*)&fnThreadFun,NULL);
样式似乎也不行,gcc编译时不会出错,但是用g++就会有问题(也会报告上面错误。),究其原因就是C语言编译器允许隐含性的将一个通用指针转换为任意类型的指针,而C++不允许

From:http://www.metsky.com/archives/550.html
背景:调试大的程序时,经常会设置很多断点。但一旦退出gdb,这些断点会全部丢失,再调试时又得重新设置断点,费时费力。gdb断点保存势在必行。
实践如下:
vi bp.list
set follow-fork-mode child
b  187
b 194
b 290    

后用-x命令载入这个断电的列表:

GNU gdb Fedora (6.8-37.el5)
Copyright (C) 2008 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu"...
Breakpoint 1 at 0x4025de: file multipepollserver.cpp, line 187.
Breakpoint 2 at 0x4026cf: file multipepollserver.cpp, line 194.
Breakpoint 3 at 0x402c2a: file multipepollserver.cpp, line 290.

有时进程退出有问题,于是得杀死,其shell一行解决:
ps aux|grep httpmut|grep -v grep|awk '{print "kill -9 "$2 }'
kill:

——————————————————————————————————————————————————————————
一、Share: gdb断点保存
调试大的程序时,经常会设置很多断点。但一旦退出gdb,这些断点会全部丢失,再调试时又得重新设置断点,费时费力。
我们可能利用gdb的-x参数来载入所有预设的断点,步骤如下:

1.将断点保存到一个文件中,如bp.list;

2.用gdb调试时,加-x参数载入上述文件。这相当于是gdb的一个批处理功能,因此你还可以在上述文件中加上其他你经常要用到的命令。

For example:

bash-3.00$ cat bp.list
b main
b 8

bash-3.00$ g++ -g test.cpp
bash-3.00$ gdb ./a.out -x bp.list -tui

GNU gdb 6.6
Copyright (C) 2006 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB.  Type "show warranty" for details.
This GDB was configured as "sparc-sun-solaris2.10"...
Breakpoint 1 at 0x11000: file test.cpp, line 26.
Breakpoint 2 at 0x10e28: file test.cpp, line 8.
(gdb)

Enjoy it~


例如,你每次启动gdb,想在main 函数处设断点

编辑一个文件比如叫   a
a中输入  
br   main
保存

gdb   你的可执行文件   -x   a就自动执行设断点了。

这相当于是gdb的一个批处理功能,你还可以在文件中加上其他你经常要用到的命令

只要用-x   参数加批处理文件运行就可以了


来自:http://blog.csdn.net/rxl2008/article/details/6273664

http://topic.csdn.net/t/20041117/17/3562393.html
可以把一些需要用到的命令写到一个文件中,运行gdb的时候读取之就ok了。

6 楼datuhao(峡谷)回复于 2004-11-18 19:22:14 得分 90
例如  
  你每次启动gdb   ,想在main   函数处设断点  
    
  编辑一个文件比如叫   a  
  a中输入    
  br   main  
  保存  
    
  gdb   你的可执行文件   -x   a就自动执行设断点了。  
    
  这相当于是gdb的一个批处理功能,你还可以在文件中加上其他你经常要用到的命令  
    
  只要用-x   参数加批处理文件运行就可以了



二、gdb单文件多文件断点设置及断点管理:
摘自:http://blog.163.com/xychenbaihu@yeah/blog/static/13222965520112179264986/




三、GDB通过自定义命令实现一次执行多个命令
今天,想在gdb一次执行next和p num_caches两条命令,尝试

next; p num_cache

等基于分割符的命令无效后,查了下,需要通过自定义命令实现,具体如下:

(gdb) next;p num_caches

Invalid character ';' in expression.

(gdb) define myfun

Type commands for definition of "myfun".

End with a line saying just "end".

>next

>p num_caches

>end

(gdb) myfun

731           cpus[j].dcache->owner = (struct godson2_cpu *)&cpus[j];

$4 = 3

另外,有些常用的命令组合可以在~/.gdbinit中定义

原文:http://mblog.sigma.me/2011/09/22/gdb-run-multi-cmd.html
背景:调试一个多进程学习的小程序,发出用gdb调试,出现:gdb调试时No symbol "var" defined in current context,if(strncmp(requestHeaderURI,TASKSURI,strlen(requestHeaderURI)) == 0){//上传分片上报链接 发现在点问题,于是查了下网络,同时发现宏好像不适合用这个函数作比较:char *strncpy(char *dest, const char *src, size_t n);。
(gdb) p requestHeaderURI
$1 = 0xa6bc240 "/task"
(gdb) p TASKSURI
No symbol "TASKSURI" in current context.
点击在新窗口中浏览此图片
————————————————————————————

在编译程序时 加上 -gdwarf-2 -g3 参数 即可。
如 gcc -gdwarf-2 -g3 sed sed.o

————————————————————————————


宏定义#define APLLCON0 *((volatile unsigned int *)0xFF500100),值为虚拟地址

问题:

gdb跟踪调试想查看该宏的值时,如下提示:No symbol “APLLCON0” in current context.


分析:

参考http://blog.csdn.net/jibing57/article/details/7439631

编译器默认没有把宏定义扩展信息编译进二进制文件。

通过man gcc查看说明,如下
点击在新窗口中浏览此图片

编译时需添加-gdwarf-2和-g3两个参数。

加了-g3的参数后,gcc编译的时候,会将扩展的debug 信息编译进二进制文件里面,包括宏定义信息。

结论:

在CFLAGS参数后添加-g3 -gdwarf-2参数
点击在新窗口中浏览此图片

重新编译、gdb调试宏,如下
点击在新窗口中浏览此图片
来自:http://blog.csdn.net/zhangjs0322/article/details/39666889

开始实践如下:
(gdb) set follow-fork-mode child
(gdb) b 290
Breakpoint 1 at 0x402bd9: file multipepollserver.cpp, line 290.
(gdb) r
..............................
294                         if(strncmp(requestHeaderURI,TASKSURI,strlen(requestHeaderURI)) == 0){//上传分片上报链接
(gdb) n
295                             printf("上传分片上报链接");
(gdb) n
线程捕获到生产出来的产品,consumer thread tid=1086941504 get  in bp=-1
298                         if(strncmp(requestHeaderURI,SLICEURI,strlen(requestHeaderURI)) == 0){//上传各分片的链接
(gdb) p requestHeaderURI
$1 = 0xd7df240 "/task"
(gdb) p TASKSURI
上传分片上报链接线程捕获到生产出来的产品,consumer thread tid=1086941504 get  in bp=-2
$2 = "/task"

如果去掉生成点o文件里的参数,只保留最后生成的可执行文件是不行的,实践证明,得在生成.o时就加上后,在后面合并时不加也成。(也就是说最后生成的.o里得有,否则,最后一步及时加上也是不行的。)
MakeFile:
multipepollserver:multipepollserver.o memorypool.o
    /usr/bin/g++44 -Wall -g -o multipepollserver  multipepollserver.o memorypool.o -lrt -lpthread -lmemcached                                                                                        
multipepollserver.o:multipepollserver.cpp memorypool.h
    /usr/bin/g++44 -Wall -g3 -gdwarf-2 -c -g multipepollserver.cpp  -std=c++0x
memorypool.o:memorypool.cpp memorypool.h
    /usr/bin/g++44 -Wall -g3 -gdwarf-2 -c -g memorypool.cpp

clean:
    rm -f multipepollserver memorypool.o  multipepollserver.o

实践证明,加这一句上,下面生成点O不加也是不行的:
/usr/bin/g++44 -Wall -g -o multipepollserver  multipepollserver.o memorypool.o -lrt -lpthread -lmemcached    
————————————————————————————————————————————————————————————————————————


其他参考:
来自:http://www.sudu.cn/info/index.php?op=article&id=260892
来自:http://blog.csdn.net/littlefang/article/details/6293448
来自:http://blog.sina.com.cn/s/blog_6cee149d0100ohvl.html
背景:centos一兄弟把那个/etc/sudoer给权限变更了,于是否,出现sudo su -因为权限进入不了root,sudo su - sudo: /etc/sudoers is mode 0640, should be 0440 ,于是否,查了一下网络,有下面两种解决办法,特别是我自己有一个方法,那就是我有一个c文件是有root的权限,它能以root的权限让php去执行这个popen的类windows的cmd命令,于是在没有root密码的情况下也能修改这个文件,解决了问题。
ubuntu或者CentOS中,/etc/sudoer 的权限为 0440时才能正常使用,否则sudo命令就不能正常使用。出现类似:sudo: /etc/sudoers is mode 0640, should be 0440 的对话。
解决办法:
1、Ctrl+Alt+F1   进入文本模式。用超级用户登录,如root
2、输入:chmod 0440 /etc/sudoers  。Enter
3、exit 退出
4、Ctrl+Alt+F7 返回图形模式。
5、在试试sudo命令,可以用了

P:其实另开一个端口,su -进入root,然后chmod 0440 /etc/sudoers  
效果是一样的

example:
[BIngo@windows ~]$ sudo chmod u+w /etc/sudoers
口令:
[BIngo@windows ~]$ ls -l /etc/sudoers
-rw-r----- 1 root root 3210 11-16 02:40 /etc/sudoers
[BIngo@windows ~]$ sudo chmod u-w /etc/sudoers
sudo: /etc/sudoers is mode 0640, should be 0440
[BIngo@windows ~]$ ls -l /etc/sudoers
-rw-r----- 1 root root 3210 11-16 02:40 /etc/sudoers

另开端口
[root@windows ~]# chmod 0440 /etc/sudoers
[root@windows ~]# exit
[BIngo@windows ~]$ ls -l /etc/sudoers
-r--r----- 1 root root 3210 11-16 02:40 /etc/sudoers

方法二(不是每台机器都有我这样的二进制,我是为了显示svn的版本号才临时用php调这个c,再用php调shell下的svn命令获取项目代码位置里的svn的版本号):
-rwsrwxrwx 1 root root 11711 Oct  9 17:29 resetServerAndOptSVN //有root权限,它会调一个php文件,这个php的shell也有root权限,于是我只对php作了修改即可:
vi resetServerAndOptSVN.php


./resetServerAndOptSVN disvnver jack
于是,Ok了,这块主要是利用这个c编译的文件有root权限,让它去修改了权限,于是解决了问题~
背景:删除一些vim的临时文件及批量文件修改时间,有用xargs的也有用exec......但是这个命令的后面这一部分得小心点写,有一个空格。
第一:花括号}后面必须得有空格.
第二:最后斜杠后面必须得有分号。
第三:exec前面有一个中横线,否则也不行,三者必须要注意。



如:
#!/bin/bash
Redisdb_file=/data/redis/6403/redis.rdb
Redisbak_dir=/data/bak/redis/6403
Bak_time=`date +%Y%m%d%H%M`
mkdir -p $Redisbak_dir
/bin/cp -rf $Redisdb_file $Redisbak_dir/redis.rdb.$Bak_time
find $Redisbak_dir -name "redis.db.201*" -mtime +30 -exec rm -rf {} \;

+ /bin/cp -rf /data/redis/6403/redis.rdb /data/bak/redis/6403/redis.rdb.201610262250
+ find /data/bak/redis/6403 -name 'redis.db.201*' -mtime +30 -exec rm -rf '{}' ';'
-----------------------------------------------------------------------------------------------------------------------------------
[root@iZ25dcp92ckZ jackxiang.com]# find . -name "*.php" -exec grep "messagebox-bottom" {} \;
          <div class="messagebox-bottom">
  <div class="messagebox-bottom"><a href="javascript: window.history.back();">{$lnc[263]}</a> | <a href="index.php">{$lnc[88]}</a> {admin_plus}</div>
  <div class="messagebox-bottom"><a href="javascript: window.history.back();">{$lnc[263]}</a> | <a href="index.php">{$lnc[88]}</a> {admin_plus}</div>


[root@iZ25dcp92ckZ jackxiang.com]# find . -name "*.php" -exec grep -lr -A3 "您目前的用户组是" {} \;
./lang/zh-cn/common.php

======================这儿不得不说xargs和-exec的区别=================================
1)-exec里的{} 相当于一个变量,于是grep时是每次针对单个文件的,所以没有文件名显示。
2)而xagrs是管道,则grep认为是一堆文件进行grep,于是默认就有文件名。


-exec就像这样指定了文件名,当然没有文件名存在了,在使用时根据实际情况进行使用:

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








下面这两种情况都是没法执行得到的,如下:
[root@localhost test]# find . -ctime -1 -exec ls -l  {} \ ;
find: missing argument to `-exec'

[root@localhost test]# find . -ctime -1 -exec ls -l  {} \
>

所以,必须得要注意,而用xargs来做这个就不用那么多事了:
find . -mtime +30 | xargs rm -f
每天运行一次,清理半月外的文件,予以删除:

==================================
[root@localhost ~]# find /tmp -type f    
/tmp/.X0-lock
/tmp/test.pcap
[root@localhost ~]# find /tmp -type f|xargs echo
/tmp/.X0-lock /tmp/test.pcap


exec选项后面跟随着所要执行的命令或脚本,然后是一对儿{ },一个空格和一个\,最后是一个分号。

[root@localhost ~]# find /tmp -type f -exec ls -l {} \;
-r--r--r-- 1 root root 11 Aug 21  2014 /tmp/.X0-lock
-rw-r--r-- 1 root root 24 Mar 10 10:42 /tmp/test.pcap
[root@localhost ~]# find /tmp -type f -exec ls -l {} ;
find: missing argument to `-exec'
[root@localhost ~]# find /tmp -type f -exec ls -l {} \;
-r--r--r-- 1 root root 11 Aug 21  2014 /tmp/.X0-lock
-rw-r--r-- 1 root root 24 Mar 10 10:42 /tmp/test.pcap


阅读全文
Q:
C语言如何比较两个【字符】或者【字符串】是否相等?
A:
比较字符可以直接使用==比较操作符,如:
char c1='a',c2='b';
if(c1==c2) printf("%c is same as %c.",c1,c2);
else printf("%c is different to %c",c1,c2);

若是字符串,则需要使用字符串函数了,strcmp
char s1[]="abc",s2[]="xyz";
if(strcmp(s1,s2)==0) printf("%s is same as %s.",s1,s2);
也可以忽略大小写来比较,使用函数stricmp 中间的i意思是ignore case sensitive
还可以指定长度比较,strncmp,如:
char s1[]="abc",s2[]="abcdefg";
if(strncmp(s1,s2,3)==0) printf("first 3 characters are same");
若不是从开头位置开始比较,如:
char s1[]="abc",s2[]="xyzabc"
if(strncmp(s1,&s2[3],3)==0) 就是比较s1和s2的第3个字符开始的内容

Egg:
#include <string.h>

char s1[10],s2[10];
...
if(strcmp(s1,s2)==0)
printf("两字符串相等\n");


string.h 头文件中就有比较函数,可以用来比较是否相等

来自:http://zhidao.baidu.com/link?url=9gRfWtoqGKzO_Y-aSb5H56QDSkKTblfzFYBoWrggRtxNaXSF3YI1MSo_gnsYvsoVdL_bN4AqEULfDLKMLvZtoq
背景:对http 80端口的监控是必须的,无论是开发时接口间调用,还是在线上弱水三千只取一瓢,对接口的侦测,我国的网侦部门对我们的行为控制,从来没有停止过,这儿请的不是tcpdump,而是有一个抓取http流量的类似tcpdump的数据包嗅探工具,httpry捕获HTTP数据包,并且将HTTP协议层的数据内容以可读形式列举出来。当前linux两个系统比较常用一个是centos一个是debian,这里都有,请看下面讲述即可。


Fedora、centos、RHEL系统需要安装EPEL源
$ sudo yum install httpry
也可以源码编译
$ sudo yum install gcc make git libpcap-devel
$ git clone https://github.com/jbittel/httpry.git
$ cd httpry
$ make
$ sudo make install


下载软件包:
yum install httpry
http://mirrors.neusoft.edu.cn/epel/6/x86_64/httpry-0.1.8-1.el6.x86_64.rpm: [Errno 14] PYCURL ERROR 22 - "The requested URL returned error: 503 Service Temporarily Unavailable"
尝试其他镜像。
httpry-0.1.8-1.el6.x86_64.rpm                                                                                                                                                 |  35 kB     00:00    
运行 rpm_check_debug
执行事务测试
已安装:
  httpry.x86_64 0:0.1.8-1.el6                                                                                                                                                                        
完毕!
阅读全文
背景:我很喜欢在命令行调试API,返回数据都是JSON格式的。打印出来的内容太痛苦了,如:{"status":200,"data":[{"id":1000,"name":"John"}{"id":1004,"name":"Tom"}]},有木有工具打印个易读的样式,这样的


实践一:
答:可以使用python的json.tool!
cat json|python -mjson.tool

cat json|python -mjson.tool
python: module json.tool not found
json是python3内置模块,在包libpython3.3-stdlib中提供。
centOS的默认的python版本是V2.4.3,但运行json库也好需要的版本是3以上,linux(CentOS)下升级python3.3:
http://lovebeyond.iteye.com/blog/1770476 ,后面升级后就Ok了,自带这个包,相当靠谱~  AddTime:2015-03-09


echo '{"status":200,"data":[{"id":1000,"name":"John"},{"id":1004,"name":"Tom"}]}'|python -mjson.tool
Vim中格式化json数据:
命令模式下
#!python -m json.tool
可以映射快捷键,如Ctrl+F6,编辑vimrc:

“ Format JSON data using python module json.tool
map <C-F6> :#!python -m json.tool<CR>

vim调用python格式化json数据:


实践二,根据1接合windows使用curl命令输出json并格式化的方法:
windows中使用curl命令需要下载curl工具

下载地址:http://curl.haxx.se/download.html

请选择不带SSL的版本,否则还需要安装SSL的支持包

我下载的版本 http://www.paehl.com/open_source/?CURL_7.28.1
下载后解压,将exe文件拷贝到 C:\windows\system32目录下即可在cmd中直接调用

我使用linux下成功的相同命令去发现报错如下:



网上查发现是引号的原因,

例如linux下成功命令格式如下:

来自:http://blog.csdn.net/lipei1220/article/details/8536520
http://blog.longwin.com.tw/2012/12/cli-python-json-formatter-2012/
http://blog.csdn.net/yuechuzhao/article/details/24460781
http://openwares.net/linux/vim_call_python_format_json.html







————————————————————linux(CentOS)下升级python3.3———————————————————————————
CentOS下的Python版本一般都比较低,很多应用都需要升级python来完成。我装的centOS的默认的python版本是V2.4.3,但运行node.js需要的版本是2.5以上。

1。下载python3.3安装包:wget http://www.python.org/ftp/python/3.3.0/Python-3.3.0.tgz

2。解压安装包:tar -zxvf Python-3.3.0.tgz
  

3。进入解压后目录:cd Python-3.3.0


4。创建安装目录:mkdir /usr/local/python3.3
  

5。编译安装:./configure --prefix=/usr/local/python3.3

6。执行:make && make install

7。此时已完成新版本的安装,但由于老版本还在系统中,所以需要将原来/usr/bin/python链接改为新的连接:a.先修改老的连接,执行:mv /usr/bin/python /usr/bin/python_bak。b.再建立新连接: ln -s /usr/local/python3.3/bin/python3.3 /usr/bin/python

8。查询python版本,执行:python

显示如下:
Python 3.3.0 (default, Jan 16 2013, 17:52:44)
[GCC 4.1.2 20071124 (Red Hat 4.1.2-42)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>>
已安装成功了。恭喜你。

实际情况,一堆老版本,还得都给挪动一下,否则还是2.7啥的:
/usr/bin/python2.4
mv /usr/bin/python2.4  /usr/bin/python2.4_bak
ln -s /usr/local/python3.3/bin/python3.3 /usr/bin/python2.4

/usr/local/bin/python2.7
mv /usr/local/bin/python2.7 /usr/local/bin/python2.7_bak
ln -s /usr/local/python3.3/bin/python3.3 /usr/local/bin/python2.7

实践来源:http://lovebeyond.iteye.com/blog/1770476


最后,json显示结构化Ok了:
[root@test Python-3.3.0]# echo '{"status":200,"data":[{"id":1000,"name":"John"},{"id":1004,"name":"Tom"}]}'|python -mjson.tool
{
    "data": [
        {
            "id": 1000,
            "name": "John"
        },
        {
            "id": 1004,
            "name": "Tom"
        }
    ],
    "status": 200
}

再结合Curl这个命令行显示一把,实践如下:
cat json.php

shell访问,直接访问json是一行,后面直接加上python的解析后变成了一个格式化的json串显示出来了,达到了目的,如下:
[root@test tools.jackxiang.com]# curl -H"Host:t43.jackxiang.com" "http://192.168.109.8/json.php"
    {  "status":200,  "data":  [  {  "id":1000,  "name":"John"  },  {  "id":1004,  "name":"Tom"  }  ]  }  [root@test tools.jackxiang.com]# curl -H"Host:t43.jackxiang.com" "http://192.168.109.8/json.php"                            vi json.php
[root@test tools.jackxiang.com]# curl -H"Host:t43.jackxiang.com" "http://192.168.109.8/json.php" | python -mjson.tool  
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100   106    0   106    0     0  51381      0 --:--:-- --:--:-- --:--:--     0
{
    "data": [
        {
            "id": 1000,
            "name": "John"
        },
        {
            "id": 1004,
            "name": "Tom"
        }
    ],
    "status": 200
}


最后,当python升级到3后,yum出现:except KeyboardInterrupt, e:
问题:
——————————————————————————————————
[root@name user]# yum
File "/usr/bin/yum", line 30
except KeyboardInterrupt, e:
^
原因:
这是因为yum采用python作为命令解释器,这可以从/usr/bin/yum文件中第一行#!/usr/bin/python发现。而python版本之间兼容性不太好,使得2.X版本与3.0版本之间存在语法不一致问题。而CentOS 5自带的yum采用的是python2.4,当系统将python升级到2.6或3.0后,出现语法解释错误。
解决办法:
很简单,一是升级yum,一是修改yum的解释器为旧版本python2.4(如果你没有采用覆盖升级的话)
升级yum的作法就不详述了;
修改yum的解释器为旧版本python2.4:
     vi /usr/bin/yum

     将第一行"#!/usr/bin/python" 改为 "#!/usr/bin/python2.4"即可,我自己是修改:
      /usr/bin/python2.4_bak  //前面挪动到这儿了,实践是OK的~

摘自:http://blog.sina.com.cn/s/blog_67d6a2650100jiaw.html
背景:做日志分析,linux C 的开发环境,在对每行日志进行处理的时候,手下一个小伙用的是逐字节拆分成字段(也就是指针)。刚开始没注意,后来每天10几G的日志上来后,发现除了速度特别慢以外,还经常出问题,遇到错误格式的日志就直接崩溃。。。从文件读取数据是一件很麻烦的事,所幸有sscanf()函数,对网络输入数据也就是从一个字符串中读进与指定格式相符的数据并进行分组也是可行的。

在做一道九度上机题时,突然发现sscanf()函数非常有用,就顺便从网上搜集资料整理一下。
       sscanf() 的作用:从一个字符串中读进与指定格式相符的数据.
原型: int sscanf (const char *str,const char * format,........);
说明: sscanf()会将参数str的字符串根据参数format字符串来转换并格式化数据。转换后的结果存于对应的参数内。
         成功则返回参数数目,失败则返回0。
注意:sscanf与scanf类似,都是用于输入的,只是后者以键盘(stdin)为输入源,前者以固定字符串为输入源。
大家都知道sscanf是一个很好用的函数,利用它可以从字符串中取出整数、浮点数和字符串等等。它的使用方法简单,特别对于整数和浮点数来说。
这里就举几个经常用到的例子来说明他的用法,便于大家深刻理解他的用法.



[root@test sscanf]# gcc sscanf.c
[root@test sscanf]# ./a.out
用法一
str = 1234
用法二
time = 2013-2-13 14:55:34
用法三
str = 12345
用法四
str = acc
用法五
str = 12345
用法六
str = 12345+


同进,我想把http请求里的get的串取出来,怎么办?

编译运行调试:
[root@test sscanf]# gcc sscanf.c      
[root@test sscanf]# ./a.out
用法七
str = task


来自:http://blog.csdn.net/sjf0115/article/details/8579935
开始前我要先做个澄清:这篇文章同Linus Torvalds这种死忠C程序员吐槽C++的观点是不同的。在我的整个职业生涯里我都在使用C++,而且现在C++依然是我做大多数项目时的首选编程语言。自然的,当我从2007年开始做ZeroMQ(ZeroMQ项目主页)时,我选择用C++来实现。主要的原因有以下几点:

1.  包含数据结构和算法的库(STL)已经成为这个语言的一部分了。如果用C,我将要么依赖第三方库要么不得不自己手动写一些自1970年来就早已存在的基础算法。

2.  C++语言本身在编码风格的一致性上起到了一些强制作用。比如,有了隐式的this指针参数,这就不允许通过各种不同的方式将指向对象的指针做转换,而那种做法在C项目中常常见到(通过各种类型转换)。同样的还有可以显式的将成员变量定义为私有的,以及许多其他的语言特性。

3.  这个观点基本上是前一个的子集,但值得我在这里显式的指出:用C语言实现虚函数机制比较复杂,而且对于每个类来说会有些许的不同,这使得对代码的理解和维护都会成为痛苦之源。

4.  最后一点是:人人都喜欢析构函数,它能在变量离开其作用域时自动得到调用。阅读全文
背景:对于文件块验证,或字符串的传输是否在网络中修改过,这儿有各种方法,MD5、SHA1、CRC32这三个用于检测文件是否被修改过,哪个可靠性最高?我看特别是分片上传这块,有的是md5,有的是sha1,有的是crc的验证,如优酷(是crc的)、百度云、126的邮箱大附件上传等都有这么一个环节~于是,在网上找相关文章了解一下其不同及性能上的差别。

MD5 和SHA1的基本原理都是一样的,都是将一个文件按照一定的算法计算后得到一个固定位数的数据,这个数据就是这个文件的(MD5,SHA1)值。而且这个值是唯一的,也就是说只有这个文件经过计算后能够得到这个值,里面哪怕有一个标点的改动所计算的值的差别都会很大。只需要在本地再进行一次MD5,SHA1的计算和原值比较即可知道源文件是否完整。CRC校验通常是将CRC的校验码放在数据文件的后面一同发送给接受方,接收方再次通过计算来判定数据的完整性。
目前如果用于加密领域,SHA的安全性能最高。如果你的可靠性是指文件的完整性,那么个人觉得MD5和SHA1要比CRC32好一些。
————————————————————————————————————————————————————————————————————————————
一、MD5与SHA算法
    Hash函数又称杂凑函数,用于摘要算法,它是将不定长的明文信息经过复杂的运算得到一个定长的数值,这就是“签名”。摘要算法与一般的对称或非对称加密算法不同,它并不用于防止信息被窃取,而是用于证明原文的完整性和准确性,也就是说,数字签名主要是用于防止信息被篡改。

由于Hash函数产生定长的数字签名,其结果是个有限的集合,而待签名的明文信息可以是计算机网络上传输的任意信息,也就是说,明文信息是一个无限集合,两个集合之间其实无法构成一一对应的关系,总会有多个明文信息产生相同的数字签名的情况发生,这就是所谓的“碰撞”。不过Hash函数的可靠性在概率上仍可以算法的健壮性来保证,数字签名类似指纹,只要选择足够全的算法,产生碰撞的概率就会足够小,可令现代最先进的计算设备也找不出“碰撞”,这样算法就不会被破解了。

     MD5(RFC1321)诞生于1991年,全称是“Message-Digest Algorithm信息摘要算法)5”,由MIT的计算机安全实验室和RSA安全公司共同提出,之前已经有MD2、MD3和MD4几种算法。MD5克服了MD4的缺陷,生成128bit的摘要信息串,出现之后迅速成为主流算法,并在1992年被收录到RFC中。

MD5算法是1991年发布的一项数字签名加密算法,它当时解决了MD4算法的安全性缺陷,成为应用非常广泛的一种算法。作为Hash函数的一个应用实例。

SHA诞生于1993年,全称是安全散列算法(Secure Hash Algorithm),由美国国家安全局(NSA)设计,之后被美国标准与技术研究院(NIST)收录到美国的联邦信息处理标准(FIPS)中,成为美国国家标准,SHA(后来被称作SHA-0)于1995被SHA-1(RFC3174)替代。SHA-1生成长度为160bit的摘要信息串,虽然之后又出现了SHA-224、SHA-256、SHA-384和SHA-512等被统称为“SHA-2”的系列算法,但仍以SHA-1为主流。

SHA-1的应用范围或许比MD5更加广泛,其安全性较MD5要高出很多。SHA-1是美国国家标准技术研究院(NIST)与美国国家安全局(NSA)共同设计的,一些重要的场合都选择SHA-1来做数字签名。美国政府更是早在1994年就开始采用了SHA-1算法。

MD5和SHA-1是当前应用最为广泛的两种散列算法。常见的Unix系统口令以及多数论坛/社区系统的口令都是经MD5处理后保存其摘要信息串,在互联网上,很多文件在开放下载的同时都提供一个MD5的信息摘要,使下载方(通过MD5摘要计算)能够确认所下载的文件与原文件一致,以此来防止文件被篡改。

    MD5和SHA-1还常被用来与公钥技术结合来创建数字签名。当前几乎所有主要的信息安全协议中都使用了SHA-1或MD5,包括SSL(HTTPS就是SSL的一种应用)、TLS、PGP、SSH、S/MIME和IPSec,因此可以说SHA-1和MD5是当前信息安全的重要基础之一。

    不过,从技术上讲,MD5和SHA-1的碰撞可在短时间内被求解出并不意味着两种算法完全失效。例如,对于公文的数字签名来说,寻找到碰撞与寻找到有特定含义的碰撞之间仍有很大的差距,而后者才会使伪造数字公文成为现实。但无论如何,王小云教授所掌握的方法已经为短时间内寻找到MD5或SHA-1的碰撞成为可能,这足以使经过MD5或SHA-1处理的数字签名再也难以成为法律认可的依据。

MD5和SHA-1就曾经被认为是足够安全的Hash算法。虽然早在1994年就有研究报告指出,如果用运算能力最强的机器,平均用24天就可能找到一个MD5的碰撞,但这个方法的效率和成本在现实中并不具备实际的意义。王小云在接受本报记者独家采访时透露,她独创的“模差分”算法可以用一般性能的计算机在两个小时内就找到MD5的碰撞,已经为实际应用提供了可能。

来自:http://blog.csdn.net/liyangbing315/article/details/5682107

二、微软出品:MD5和SHA1值验证命令行工具
基本使用方法:
fciv.exe  myfilm.iso  -wp -md5 -xml mydb.xml
该命令可以计算myfilm.iso的md5值,并且保存到mydb.xml当中,同时会保存该文件的名称,-wp的作用是去掉文件的路径信息仅仅保存文件名

fciv.exe -list -md5 -xml mydb.xml
打印mydb.xml当中的md5值以及相应的文件名称,它的显示格式也比较特别,首先打印md5值,随后是文件名称

fciv.exe d:\mymusic\   -tpye *.mp3 -wp -md5 -xml mymusic.xml
计算d盘mymusic文件夹下面,所有以MP3结尾的文件的md5值并且保存到mymusic.xml当中

由于这是一个命令行工具,因此可以批处理的方式,大量自动化计算各种md5值。

工具下载地址和基本的使用方法介绍见下面的链接
http://support.microsoft.com/kb/841290
DownLoad Url:http://download.microsoft.com/download/c/f/4/cf454ae0-a4bb-4123-8333-a1b6737712f7/Windows-KB841290-x86-ENU.exe

摘自:http://blog.chinaunix.net/uid-20385936-id-3841729.html

三、PHP md5 vs sha1 性能测试
先上代码:

Win7 PHP 5.3.5 cli 下连续三次的输出
D:\test>php md5-vs-sha1.php
0.36025786399841
0.47072792053223

D:\test>php md5-vs-sha1.php
0.36374092102051
0.47682809829712

D:\test>php md5-vs-sha1.php
0.37186717987061
0.55312395095825
Ubuntu Server 11.04 PHP 5.3.5 cli 下的连续三次的输出
  
$ php md5-vs-sha1.php
0.4476261138916
0.45379900932312

$ php md5-vs-sha1.php
0.43760395050049
0.45441389083862

$ php md5-vs-sha1.php
0.44000005722046
0.53387594223022
由此可见,md5 会比 sha1 稍微快一点点,两者都不会造成性能问题。
From:http://my.oschina.net/heiing/blog/122914
背景:用新版本的编译器编译时,原来没有报任何错和警告的代码,现在居然报出警告了,
之前是:

无错误,现在是新的gcc v4.4的编译器编译时候出现警告了,如下:


警告如下:
multipepollserver.cpp:530: warning: deprecated conversion from string constant to ‘char*’
multipepollserver.cpp:536: warning: deprecated conversion from string constant to ‘char*’
multipepollserver.cpp:537: warning: deprecated conversion from string constant to ‘char*’

原来是定义pid变量时,新的gcc版本需要加上const,也就是:

为何要加,下面文章有描写道:
阅读全文
该软件是Mac下非常方便的Web调试工具与windows下的Fiddler一样,用过Fiddler的人应该都知道其功能对于web开发来说是多棒。 如果你不知道Fiddler可以看这里http://blog.thinkjs.net/archives/79

From:http://download.csdn.net/download/chuandeng99/4505164
一、记录CentOS 7与以往不同的地方
由于公司这一期的产品准备支持的环境有CentOS 7、MySql 5.6、Java 8、Tomcat 8等等,并且因为人员严重不足,我本月的开发任务在原有的基础上又加上了好多环境检证的工作。
  因为在这次环境检证过程中遇到了不少困难,特此记录一下。
  重点:记录CentOS 7与以往不同的地方
  1.取消ifconfig,使用ip addr 查看IP地址。  
  2.使用firewalld 取代 iptables。
  3.系统默认编码设置文件,由/etc/sysconfig/i18n  更改为 /etc/locale.conf
___________________________详细介绍使用感受__________________________
因为系统安装时网络连接设置的自动获取,先改成静态ip。配置方法如下:
  第一步,vi /etc/sysconfig/network-scripts/ifcfg-enp0s25;
  设置内容:
  
  解释:  
IPADDR0 --> ip
GATEWAY0 --> 网关
DNS1 -->DNS
  
  第二步,重启网络服务 -->service network restart(特别重要,千万不要忘记。)
  第三步.查看ip ip addr,再 ping 一下网络。这是网络配置基本就完成了。
  事情进展到这里貌似也没什么难过的坎,我开始配置防火墙。先使用 iptables status 查看防火墙状态,
  
  我去,什么鬼?我敲错了?有一次仔细核对了每一个字母,完全没错啊!!!不管怎么说,先看一下iptables脚本是否还存在吧。
  
  咦,iptables脚本不见了。不用多想一定是CentOS 7使用了新型的防火墙,立即百度。
  ※度娘解惑:CentOS 7使用firewalld 取代 iptables。使用命令行工具firewalld-cmd获取firewalld状态,$ firwall-cmd --state。
摘自:http://www.linuxidc.com/Linux/2015-01/111998.htm

————————————————————————————————————————————————————————————
二、修改开机启动顺序:
http://wenku.baidu.com/link?url=HXBiVyBOB_p1oAEN0Wunreof9Fff9dy4s6abRC_Zqq6Cm1ZbOvmgXrcQ3kC3OTLmDq-FwrjeK-Fw9zgoZ3yBGGyA_ikGSRtjvhjcS_dEaQu

————————————————————————————————————————————————————————————
三、 CentOS 7 巨大变动之 systemd 取代 SysV的Init
systemd是什么
首先systmed是一个用户空间的程序,属于应用程序,不属于Linux内核范畴,Linux内核的主要特征在所有发行版中是统一的,厂商可以自由改变的是用户空间的应用程序。
Linux内核加载启动后,用户空间的第一个进程就是初始化进程,这个程序的物理文件约定位于/sbin/init,当然也可以通过传递内核参数来让内核启动指定的程序。这个进程的特点是进程号为1,代表第一个运行的用户空间进程。不同发行版采用了不同的启动程序,主要有以下几种主流选择:
(1)以Ubuntu为代表的Linux发行版采用upstart。
(2)以7.0版本之前的CentOS为代表的System V init。
(3)CentOS7.0版本的systemd。
下面是CentOS6.5和CentOS7两个版本初始化进程的信息截图。
CentOS6.5采用的是systemV init
CentOS7 采用的是systemd:
Linux内核加载启动后,用户空间的第一个进程就是初始化进程,这个程序的物理文件约定位于/sbin/init,当然也可以通过传递内核参数来让内核启动指定的程序。这个进程的特点是进程号为1,代表第一个运行的用户空间进程。不同发行版采用了不同的启动程序,主要有以下几种主流选择:
(1)以Ubuntu为代表的Linux发行版采用upstart。
(2)以7.0版本之前的CentOS为代表的System V init。
(3)CentOS7.0版本的systemd。
下面是CentOS6.5和CentOS7两个版本初始化进程的信息截图。
CentOS6.5采用的是systemV init
CentOS7 采用的是systemd

摘自:http://blog.csdn.net/smstong/article/details/39317491

参考:https://blog.linuxeye.com/400.html

=======================centos7上systemd详解============================
CentOS 7继承了RHEL 7的新的特性,例如强大的systemd, 而systemd的使用也使得以往系统服务的/etc/init.d的启动脚本的方式就此改变, 也大幅提高了系统服务的运行效率。但服务的配置和以往也发生了极大的不同,同时变的简单而易用了许多。

CentOS 7的服务systemctl脚本存放在:/usr/lib/systemd/,有系统 system 和用户 user 之分, 即:/usr/lib/systemd/system 和 /usr/lib/systemd/user

配置文件

这里我们先要说明一下unit的文件位置,一般主要有三个目录:

/lib/systemd/system
/run/systemd/system
/etc/systemd/system
这三个目录的配置文件优先级依次从低到高,如果同一选项三个地方都配置了,优先级高的会覆盖优先级低的。 系统安装时,默认会将unit文件放在/lib/systemd/system目录。如果我们想要修改系统默认的配置,比如nginx.service,一般有两种方法:

在/etc/systemd/system目录下创建nginx.service文件,里面写上我们自己的配置。
在/etc/systemd/system下面创建nginx.service.d目录,在这个目录里面新建任何以.conf结尾的文件,然后写入我们自己的配置。推荐这种做法。
/run/systemd/system这个目录一般是进程在运行时动态创建unit文件的目录,一般很少修改,除非是修改程序运行时的一些参数时,即Session级别的,才在这里做修改。

服务配置

每一个服务以.service结尾,一般会分为3部分:[Unit]、[Service]和[Install],就以nginx为例吧,具体内容如下:
[Unit]
Description=nginx - high performance web server
Documentation=http://nginx.org/en/docs/
After=network.target remote-fs.target nss-lookup.target
[Service]
Type=forking
PIDFile=/usr/local/nginx/logs/nginx.pid
ExecStartPre=/usr/local/nginx/sbin/nginx -t -c /usr/local/nginx/conf/nginx.conf
ExecStart=/usr/local/nginx/sbin/nginx -c /usr/local/nginx/conf/nginx.conf
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/bin/kill -s QUIT $MAINPID
PrivateTmp=true
[Install]
WantedBy=multi-user.target
配置项说明

下面分别解释下着三部分的含义

[Unit]

Description : 服务的简单描述
Documentation : 服务文档
After= : 依赖,仅当依赖的服务启动之后再启动自定义的服务单元
[Service]

Type : 启动类型simple、forking、oneshot、notify、dbus
Type=simple(默认值):systemd认为该服务将立即启动,服务进程不会fork。如果该服务要启动其他服务,不要使用此类型启动,除非该服务是socket激活型
Type=forking:systemd认为当该服务进程fork,且父进程退出后服务启动成功。对于常规的守护进程(daemon),除非你确定此启动方式无法满足需求, 使用此类型启动即可。使用此启动类型应同时指定PIDFile=,以便systemd能够跟踪服务的主进程。
Type=oneshot:这一选项适用于只执行一项任务、随后立即退出的服务。可能需要同时设置 RemainAfterExit=yes 使得 systemd 在服务进程退出之后仍然认为服务处于激活状态。
Type=notify:与 Type=simple 相同,但约定服务会在就绪后向 systemd 发送一个信号,这一通知的实现由 libsystemd-daemon.so 提供
Type=dbus:若以此方式启动,当指定的 BusName 出现在DBus系统总线上时,systemd认为服务就绪。
PIDFile : pid文件路径
ExecStartPre :启动前要做什么,上文中是测试配置文件 -t
ExecStart:启动
ExecReload:重载
ExecStop:停止
PrivateTmp:True表示给服务分配独立的临时空间
[Install]

WantedBy:服务安装的用户模式,从字面上看,就是想要使用这个服务的有是谁?上文中使用的是:multi-user.target ,就是指想要使用这个服务的目录是多用户。
每一个.target实际上是链接到我们单位文件的集合,当我们执行

systemctl enable nginx.service
就会在 /etc/systemd/system/multi-user.target.wants/ 目录下新建一个 /usr/lib/systemd/system/nginx.service 文件的链接。

操作示例

下面是几个最常用的service操作:
# 自启动
systemctl enable nginx.service
# 禁止自启动
systemctl disable nginx.service
# 启动服务
systemctl start nginx.service
# 停止服务
systemctl stop nginx.service
# 重启服务
systemctl restart nginx.service
# 查看Unit定义文件
systemctl cat nginx.service
# 编辑Unit定义文件
systemctl edit nginx.service
# 重新加载Unit定义文件
systemctl reload nginx.service
# 列出已启动的所有unit,就是已经被加载到内存中
systemctl list-units
# 列出系统已经安装的所有unit,包括那些没有被加载到内存中的unit
systemctl list-unit-files
# 查看服务的日志
journalctl -u nginx.service    # 还可以配合`-b`一起使用,只查看自本次系统启动以来的日志
# 查看所有target下的unit
systemctl list-unit-files --type=target
# 查看默认target,即默认的运行级别。对应于旧的`runlevel`命令
systemctl get-default
# 设置默认的target
systemctl set-default multi-user.target
# 查看某一target下的unit
systemctl list-dependencies multi-user.target
# 切换target,不属于新target的unit都会被停止
systemctl isolate multi-user.target
systemctl poweroff    # 关机
systemctl reboot       # 重启
systemctl rescue    # 进入rescue模式
参考资料

create systemd unit files
NGINX systemd service file
Systemd introduction

From:https://www.xncoding.com/2016/06/07/linux/systemd.html
分页: 20/34 第一页 上页 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 下页 最后页 [ 显示模式: 摘要 | 列表 ]