无来

不管你来还是不来
我都在这里,夜夜点亮
不是为了守候
只是为了做好我自己

0%

In Cisco routers, the codes for a traceroute command reply are:

1
2
3
4
5
6
7
8
! -- success
* -- time out
N -- network unreachable
H -- host unreachable
P -- protocol unreachable
A -- admin denied
Q -- source quench received (congestion)
? -- unknown (any other ICMP message)

作者: Laruence( )
本文地址: http://www.laruence.com/2011/06/23/2057.html
转载请注明出处

其实一直想写这个系列, 但是一想到这个话题的宽泛性, 我就有点感觉无法组织.

今天我也不打算全部讲如何调试一个PHP的Core文件, 也不会介绍什么是Coredump, 选择一个相对比较简单的方向来介绍, 那就是如何从PHP的Core文件中获取一些对我们重演这个Core有帮助的信息.

在这个过程中, 会涉及到对PHP的函数调用, PHP的传参, PHP的一些全局变量的知识, 这些知识在我之前的文章中都有过涉及, 大家可以翻阅: 深入理解PHP原理之函数 深入理解PHP原理之变量作用域等等.

首先, 让我们生成一个供我们举例子的Core文件:

1
2
3
4
5
6
<?php
function recurse($num) {
recurse(++$num);
}

recurse(0);

运行这个PHP文件:

1
2
$ php test.php
Segmentation fault (core dumped)

这个PHP因为无线递归, 会导致爆栈, 从而造成 segment fault而在PHP的当前工作目录产生Coredump文件(如果你的系统没有产生Coredump文件, 那请查询ulimit的相关设置).

1
2
$ ulimit -c unlimited
$ php test.php

好, 现在, 让我们删除掉这个test.php, 忘掉上面的代码, 我们现在仅有的是这个Core文件, 任务是, 找出这个Core产生的原因, 以及发生时候的状态.

首先, 让我们用gdb打开这个core文件:

1
$ gdb php -c core.31656

会看到很多的信息, 首先让我们注意这段:

1
2
3
Core was generated by `php test.php'.
Program terminated with signal 11, Segmentation fault.

他告诉我们Core发生的原因:”Segmentation fault”.

一般来说, 这种Core是最常见的, 解引用空指针, double free, 以及爆栈等等, 都会触发SIGSEGV, 继而默认的产生Coredump.

现在让我们看看Core发生时刻的堆栈:

1
2
3
4
5
6
7
8
9
10
#0  execute (op_array=0xdc9a70) at /home/laruence/package/php-5.2.14/Zend/zend_vm_execute.h:53
53 memset(EX(CVs), 0, sizeof(zval**) * op_array->last_var);
(gdb) bt
#0 execute (op_array=0xdc9a70) at /home/laruence/package/php-5.2.14/Zend/zend_vm_execute.h:53
#1 0x00000000006ea263 in zend_do_fcall_common_helper_SPEC (execute_data=0x7fbf400210) at /home/laruence/package/php-5.2.14/Zend/zend_vm_execute.h:234
#2 0x00000000006e9f61 in execute (op_array=0xdc9a70) at /home/laruence/package/php-5.2.14/Zend/zend_vm_execute.h:92
#3 0x00000000006ea263 in zend_do_fcall_common_helper_SPEC (execute_data=0x7fbf400440) at /home/laruence/package/php-5.2.14/Zend/zend_vm_execute.h:234
#4 0x00000000006e9f61 in execute (op_array=0xdc9a70) at /home/laruence/package/php-5.2.14/Zend/zend_vm_execute.h:92
#5 0x00000000006ea263 in zend_do_fcall_common_helper_SPEC (execute_data=0x7fbf400670) at /home/laruence/package/php-5.2.14/Zend/zend_vm_execute.h:234
.....

不停的按回车, 可以看到堆栈很深, 不停的是zend_do_fcall_common_helper_SPEC和execute的重复, 那么这基本就能断定是因为产生了无穷大的递归(不能一定说是无穷递归, 比如我之前文章中介绍深悉正则(pcre)最大回溯/递归限制). 从而造成爆栈产生的Core.

Ok, 那么现在让我们看看, Core发生在PHP的什么函数中, 在PHP中, 对于FCALL_* Opcode的handler来说, execute_data代表了当前函数调用的一个State, 这个State中包含了信息:

1
2
3
4
5
6
7
8
9
(gdb)f 1
#1 0x00000000006ea263 in zend_do_fcall_common_helper_SPEC (execute_data=0x7fbf400210) at /home/laruence/package/php-5.2.14/Zend/zend_vm_execute.h:234
234 zend_execute(EG(active_op_array) TSRMLS_CC);
(gdb) p execute_data->function_state.function->common->function_name
$3 = 0x2a95b65a78 "recurse"
(gdb) p execute_data->function_state.function->op_array->filename
$4 = 0x2a95b632a0 "/home/laruence/test.php"
(gdb) p execute_data->function_state.function->op_array->line_start
$5 = 2

现在我们得到, 在调用的PHP函数是recurse, 这个函数定义在/home/laruence/test.php的第二行

经过重复验证几个frame, 我们可以看出, 一直是在重复调用这个PHP函数.

要注意的是, 为了介绍查看执行信息的原理, 我才采用原生的gdb的print来查看, 其实我们还可以使用PHP源代码中提供的.gdbinit(gdb命令编写脚本), 来简单的获取到上面的信息:

(gdb) source /home/laruence/package/php-5.2.14/.gdbinit
(gdb) zbacktrace
[0xbf400210] recurse() /home/laruence/test.php:3
[0xbf400440] recurse() /home/laruence/test.php:3
[0xbf400670] recurse() /home/laruence/test.php:3
[0xbf4008a0] recurse() /home/laruence/test.php:3
[0xbf400ad0] recurse() /home/laruence/test.php:3
[0xbf400d00] recurse() /home/laruence/test.php:3
[0xbf400f30] recurse() /home/laruence/test.php:3
[0xbf401160] recurse() /home/laruence/test.php:3
.....

关于.gdbinit, 是一段小小的脚本文件, 定义了一些方便我们去调试PHP的Core, 大家也可以用文本编辑器打开, 看看里面定义的一些快捷的命令, 一般来说, 我常用的有:

zbacktrace
print_ht**系列
zmemcheck

OK, 回归正题, 我们现在知道, 问题发生在/home/laruence/test.php的recurse函数的递归调用上了.

现在, 让我们来看看, 在调用这个函数的时候的参数是什么?

PHP的参数传递是依靠一个全局Stack来完成的, 也就是EG(argument_stack), EG在非多线程情况下就是executor_globals, 它保持了很多执行状态. 而argument_statck就是参数的传递栈, 保存着对应PHP函数调用层数相当的调用参数.

要注意的是, 这个PHP函数调用堆栈(层数)不和gdb所看到的backtrace简单的一一对应, 所以参数也不能直接和gdb的backtrace对应起来, 需要单独分析:

//先看看, 最后一次函数调用的参数数目是多少
(gdb) p (int )*(executor_globals->argument_stack->top_element - 2)
$13 = 1

//再看看, 最后一次函数调用的参数是什么
(gdb)  p **(zval **)(executor_globals->argument_stack->top_element - 3)
$2 = {value = {lval = 22445, dval = 1.1089303420906779e-319, str = {val = 0x57ad <Address 0x57ad out of bounds>, len = 7}, ht = 0x57ad, obj = {handle = 22445, handlers = 0x7}},
  refcount = 2, type = 1 '\001', is_ref = 0 '\0'}

好, 我们现在得到, 最后一次调用的参数是一个整数, 数值是22445

到了这一步, 我们就得到了这个Core发生的时刻的PHP层面的相关信息, 接下来, 就可以交给对应的PHP开发工程师来排查, 这个参数下, 可能造成的无穷大递归的原因, 从而修复这个问题..

后记: 调试PHP的Core是一个需要丰富经验的过程, 也许我今天介绍的这个例子太简单, 但是只要经常去挑战, 在遇到不懂的相关的知识的时候, 勇于去追根究底, 我相信大家终都可以成PHP Core杀手..

正则表达式,一个十分古老而又强大的文本处理工具,仅仅用一段非常简短的表达式语句,便能够快速实现一个非常复杂的业务逻辑。熟练地掌握正则表达式的话,能够使你的开发效率得到极大的提升。

正则表达式经常被用于字段或任意字符串的校验,如下面这段校验基本日期格式的JavaScript代码:

var reg = /^(\\d{1,4})(-|\\/)(\\d{1,2})\\2(\\d{1,2})$/; 
var r = fieldValue.match(reg);             
if(r==null)alert('Date format error!');


下面是技匠整理的,在前端开发中经常使用到的20个正则表达式。
  • 1、校验密码强度 密码的强度必须是包含大小写字母和数字的组合,不能使用特殊字符,长度在8-10之间。

    ^(?=.\d)(?=.[a-z])(?=.*[A-Z]).{8,10}$

  • 2、校验中文 字符串仅能是中文。

    ^[\u4e00-\u9fa5]{0,}$

  • 3、由数字、26个英文字母或下划线组成的字符串

    ^\w+$

  • 4、校验E-Mail 地址 同密码一样,下面是E-mail地址合规性的正则检查语句。

    [\w!#$%&’+/=?^_`{|}~-]+(?:\.[\w!#$%&’+/=?^_`{|}~-]+)@(?:[\w](?:[\w-][\w])?\.)+\w?

  • 5、校验身份证号码

    下面是身份证号码的正则校验。15 或 18位。

    15位:

    ^[1-9]\d{7}((0\d)|(1[0-2]))(([0|1|2]\d)|3[0-1])\d{3}$

18位:

^[1-9]\\d{5}[1-9]\\d{3}((0\\d)|(1[0-2]))(([0|1|2]\\d)|3[0-1])\\d{3}([0-9]|X)$
  • 6、校验日期 “yyyy-mm-dd“ 格式的日期校验,已考虑平闰年。

    ^(?:(?!0000)[0-9]{4}-(?:(?:0[1-9]|1[0-2])-(?:0[1-9]|1[0-9]|2[0-8])|(?:0[13-9]|1[0-2])-(?:29|30)|(?:0[13578]|1[02])-31)|(?:[0-9]{2}(?:0[48]|[2468][048]|[13579][26])|(?:0[48]|[2468][048]|[13579][26])00)-02-29)$

  • 7、校验金额 金额校验,精确到2位小数。

    ^[0-9]+(.[0-9]{2})?$

  • 8、校验手机号 下面是国内 13、15、18开头的手机号正则表达式。

    ^(13[0-9]|14[5|7]|15[0|1|2|3|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$

  • 9、判断IE的版本 IE目前还没被完全取代,很多页面还是需要做版本兼容,下面是IE版本检查的表达式。

    ^.MSIE 5-8?(?!.*Trident\/[5-9]\.0).$

  • 10、校验IP-v4地址 IP4 正则语句。

    \b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b

  • 11、校验IP-v6地址 IP6 正则语句。

    (([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))

  • 12、检查URL的前缀 应用开发中很多时候需要区分请求是HTTPS还是HTTP,通过下面的表达式可以取出一个url的前缀然后再逻辑判断。

    if (!s.match(/^[a-zA-Z]+:\/\//))
    {

    s = 'http://' + s;

    }

  • 13、提取URL链接 下面的这个表达式可以筛选出一段文本中的URL。
    ^(f|ht){1}(tp|tps):\/\/([\w-]+\.)+[\w-]+(\/[\w- ./?%&=]*)?

  • 14、文件路径及扩展名校验 验证文件路径和扩展名

    ^([a-zA-Z]\:|\\)\\([^\\]+\\)[^\/:?”<>|]+\.txt(l)?$

  • 15、提取Color Hex Codes 有时需要抽取网页中的颜色代码,可以使用下面的表达式。

    \\#([a-fA-F]|[0-9]){3,6}
  • 16、提取网页图片 假若你想提取网页中所有图片信息,可以利用下面的表达式。

    \\< *[img][^\\>]*[src] *= *[\\"\\']{0,1}([^\\"\\'\\ >]*)
  • 17、提取页面超链接 提取html中的超链接。

    (<a\\s*(?!.*\\brel=)[^>]*)(href="https?://)((?!(?:(?:www\\.)?'.implode('|(?:www\\.)?', $follow_list).'))[^"]+)"((?!.*\\brel=)[^>]*)(?:[^>]*)>
  • 18、精炼CSS 通过下面的表达式,可以搜索相同属性值的CSS,从而达到精炼代码的目的。

    ^\\s*[a-zA-Z\\-]+\\s*[:]{1}\\s[a-zA-Z0-9\\s.#]+[;]{1}
  • 19、抽取注释 如果你需要移除HMTL中的注释,可以使用如下的表达式。

  • 20、匹配HTML标签 通过下面的表达式可以匹配出HTML中的标签。

    </?\w+((\s+\w+(\s=\s(?:”.?”|’.?’|[\^’”>\s]+))?)+\s|\s)/?>

正则表达式的相关语法

下面是我找到的一张非常不错的正则表达式 Cheat Sheet,可以用来快速查找相关语法。 ![正则表达图](http://res.hillock.com.cn/web/reg1)

学习正则表达式

我在网上看到了一篇相当不错的正则表达式快速学习指南,有兴趣继续深入学习的同学可以参考。
图像

正则表达式在线测试工具

regex101是一个非常不错的正则表达式在线测试工具,你可以直接在线测试你的正则表达式哦。

学习正则表达

在电商网站中,单页Web是非常常见的一种形式,比如首页、频道页、广告页等都属于单页应用。而这种页面是由模板+数据组成。传统的构建方式一般通过静态化实现。而这种方式的灵活性并不是很好,比如页面模板部分变更了需要重新全部生成。因此最好能有一种实现方式是可以实时动态渲染,以支持模板的多变性。另外也要考虑好如下几个问题:

  • 1、动态化模板渲染支持; 2、数据和模板的多版本化:生产版本、灰度版本和预发布版本; 3、版本回滚问题,假设当前发布的生产版本出问题了如何快速的回滚到上一个版本; 4、异常问题,假设渲染模板时遇到了异常情况(比如获取Redis出问题了),如何处理; 5、灰度发布问题,比如切20%量给灰度版本; 6、预发布问题,目的是在正式环境测试数据和模板的正确性。
  • 整体架构

    静态化页面的方案如下图所示:
    [转]应用数据静态化架构高性能单页Web应用

    直接将生成的静态页推送到相关服务器即可。使用这种方式要考虑文件操作的原子化问题(即从老版本切换到新版本如何做到文件操作原子化)。

    而动态化方案的整体架构如下图所示,分为三大系统:CMS系统、控制系统和前端展示系统。
    [转]应用数据静态化架构高性能单页Web应用

    ###CMS系统
    1、在CMS系统可以配置页面的模板和数据;
    1.1、模板动态在CMS系统中维护,即模板不是一个静态文件,而是存储在CMS中的一条数据,最终发布到“发布数据存储Redis”中,前端展示系统从Redis中获取该模板进行渲染,从而前端展示系统更换了模板也不需要重启,纯动态维护模板数据;
    2、原始数据存储到“元数据存储Mysql”中即可,比如频道页一般需要:前端访问的URL、分类、轮播图、商品楼层数据等;这些数据按照相应的维度存储在CMS系统中;
    3、提供发布到“发布数据存储Redis”的控制,将CMS系统中的原始数据和模板数据组装成聚合数据(JSON存储)同步到“发布数据存储Redis”,以便前端展示系统获取进行展示;此处提供三个发布按钮:正式版本、灰度版本和预发布版本。

    目前存在如下几个问题:
    1、用户如访问http://channel.jd.com/fashion.html怎么定位到对应的聚合数据呢? 我们可以在CMS元数据中定义URL作为KEY,如果没有URL,则使用ID作为KEY,或者自动生成一个URL。
    2、多版本如何存储呢? 使用Redis的Hash结构存储即可,KEY为URL(比如http://channel.jd.com/fashion.html),字段按照维度存储:正式版本使用当前时间戳存储(这样前端系统可以根据时间戳排序然后获取最新的版本)、预发布版本使用“predeploy”作为字段,灰度版本使用“abVersion”作为字段即可,这样就区分开了多版本。
    3、灰度版本如何控制呢?这个通过控制系统的开关来控制如何灰度;
    4、如何访问预发布版本呢?比如在URL参数总带上predeploy=true,另外可以限定只有内网可以访问或者访问时带上访问密码,比如pwd=absdfedwqdqw。
    5、模板变更的历史数据校验问题?比如模板变更了,但是使用历史数据渲染该模板会出现问题,即模板要兼容历史数据的;此处的方案不存在这个问题,因为每次存储时是当时的模板快照,即数据快照和模板快照推送到“发布数据存储Redis”中。

    前端展示系统
    1、获取当前URL,使用URL作为KEY首先从本机“发布数据存储Redis”获取数据;
    2、如果没有数据或者异常则从主“发布数据存储Redis”获取;
    3、如果主“发布数据存储Redis”也发生了异常,那么会直接调用CMS系统暴露的API直接从元数据存储Mysql中获取数据进行处理。

    展示系统的伪代码

    Java代码  
    --1、加载Lua模块库  
    local template = require("resty.template")  
    template.load = function(s) return s end  
    
    --2、动态获取模板  
    local myTemplate = "<html>{* title *}</html>"  
    --3、动态获取数据  
    local data = {title = "iphone6s"}  
    
    --4、渲染模板  
    local func = template.compile(myTemplate)  
    local content = func(data)  
    
    --5、通过ngx API输出内容  
    ngx.say(content)  
    即模板和数据都是动态获取的,然后使用动态获取的模板和数据进行渲染。

    此处假设最新版本的模板或数据有问题怎么办?这个可以从流程上避免:1、首先进行预发布版本发布,测试人员验证没问题后;2、接着发布灰度版本,在灰度时自动去掉CDN功能(即不设置页面的缓存时间),发布验证OK;3、发布正式版本即可;正式版本发布的5分钟内是不设置页面缓存的,这样就可以防止发版时遇到问题,但是问题版本已经在CDN上给全部用户造成问题。当然这个流程很麻烦,可以按照自己的场景进行简化。

    控制系统
    控制系统用于版本降级和灰度发布的,当然可以把这个功能放在CMS系统中实现。
    版本降级:假设当前线上的版本遇到问题了,想要快速切换回上一个版本,可以使用控制系统实现,选中其中一个历史版本然后通知给前端展示系统即可,使用URL和当前版本的字段即可,这样前端展示系统就可以自动切换到选中的那个版本;当问题修复后,再删除该降级配置即切换回最新版本。
    灰度发布:在控制系统控制哪些URL需要灰度发布和灰度发布的比例,同版本降级类似将相关的数据推送到前端展示系统即可,当不想灰度发布时删除相关数据即可。

    数据和模板动态化

    我们将数据和模板都进行动态化存储,这样可以在CMS进行数据和模板的变更;实现了前端和后端开发人员的分离;前端开发人员进行CMS数据配置和模板开发,而后端开发人员只进行系统的维护。另外因为模板的动态化存储,每次发布新的模板不需要老重启前端展示系统,后端开发人员更好地得到了解放。

    模板和数据可以是一对多的关系,即一个模板可以被多个数据使用。假设模板发生变更后,我们可以批量推送模板关联的数据,首先进行预发布版本的发布,测试人员进行验证,验证没问题即可发布正式版本。

    多版本机制

    我们将数据和模板分为多版本后,可以实现:
    预发布版本:更容易让测试人员在实际环境进行验证;
    灰度版本:只需要简单的开关控制,就可以进行A/B测试;
    正式版本:存储多个历史正式版本,假设最新的正式版本出现问题,可以非常快速的切换回之前的版本。

    异常问题

    其中一个担心就是本机从“发布数据存储Redis”和主“发布数据存储Redis”都挂了,那么我们直接调用CMS系统暴露的HTTP服务直接从元数据存储Mysql获取数据。

    另外一个担心是数据和模板获取到了,但是渲染模板出错了,比如遇到500、503;解决方案是:使用上一个版本的数据进行渲染。

    另外还一种问题是数据和模板都没问题,但是因为一些疏忽,渲染出来的页面错乱了或者有些区域出现了空白;对于这种问题没有很好的解决方案;可以根据自己的场景定义异常扫描库,扫描当前版本有异常就发警告给相关人员,并自动降级到上一个版本。

    来源:开涛的博客

    mysql 5.5已经出来有一段时间,性能有明显提升,特别是对多核CPU的支持与TPS性能的提升。上周博主介绍了linux下编译安装mysql 5.5的步骤,安装不出意外基本没有问题。不过可能很多朋友和我一样一直用的是mysql 5.1,现在想把数据库升级成5.5了。博主根据实际操作,记录这次升级操作。

    mysql基础信息

    1、安装目录
    [root@vm-199~]# /usr/local/mysql
    2、配置文件
    [root@vm-199~]# /etc/my.cnf
    3、数据目录
    [root@vm-199~]# /data/mysql
    4、启动脚本
    [root@vm-199~]# /etc/init.d/mysql

    备份数据和安装、配置文件

    [root@vm-199~]# mysqldump -uroot -p –all-databases </root/zhangnq/mysql5.1/mysql_dbk_20140217.sql [root@vm-199~]# tar czvf mysql_5.1.60_full.tar.gz /usr/local/mysql [root@vm-199~]# tar czvf mysql_5.1.60_data_full.tar.gz /data/mysql [root@vm-199~]# cp /etc/my.cnf ./

    数据备份好后关闭mysql数据库,/etc/init.d/mysql stop,删除/usr/local/mysql文件。

    安装mysql 5.5

    具体可以参考这篇文章《Linux下编译安装Mysql-5.5的简单步骤》(http://www.sijitao.net/1563.html),安装目录、数据目录和5.1的一样,都是/usr/local/mysql

    更新配置文件

    [root@vm-199 mysql-5.5.35]# cp support-files/my-huge.cnf /etc/my.cnf

    在配置文件中添加数据目录,datadir = /data/mysql 。

    启动mysql 5.5,执行更新程序并重启mysql

    [root@vm-199 mysql-5.5.35]# /etc/init.d/mysql start [root@vm-199 mysql-5.5.35]# /usr/local/mysql/bin/mysql_upgrade Looking for 'mysql' as: /usr/local/mysql/bin/mysql Looking for 'mysqlcheck' as: /usr/local/mysql/bin/mysqlcheck Running 'mysqlcheck' with connection arguments: '--port=3306' '--socket=/tmp/mysqld.sock' Running 'mysqlcheck' with connection arguments: '--port=3306' '--socket=/tmp/mysqld.sock' mydb.t1 OK mydb.t2 OK mysql.columns_priv OK mysql.db OK mysql.event OK mysql.func OK mysql.general_log OK mysql.help_category OK mysql.help_keyword OK mysql.help_relation OK mysql.help_topic OK mysql.host OK mysql.ndb_binlog_index OK mysql.plugin OK mysql.proc OK mysql.procs_priv OK mysql.proxies_priv OK mysql.servers OK mysql.slow_log OK mysql.tables_priv OK mysql.time_zone OK mysql.time_zone_leap_second OK mysql.time_zone_name OK mysql.time_zone_transition OK mysql.time_zone_transition_type OK mysql.user OK Running 'mysql_fix_privilege_tables'... OK
    至此mysql已经更新好了。登陆mysql,检查数据是否和原来一样。

    这个mysql升级其实不复杂,其实就是重新安装一遍,然后把数据目录文件覆盖一下。不过数据库升级,主要还是得注意数据备份,防止数据和意外丢失。

    • 查找目录下的所有文件中是否含有某个字符串
      find .|xargs grep -ri "IBM"

    • 查找目录下的所有文件中是否含有某个字符串,并且只打印出文件名
      find .|xargs grep -ri "IBM" -l

    • 仅查找文件
      find . -type f|xargs grep -ri "IBM" -l

    • 查找文件为0,包括空格处理
      find . -type f -size 0c -print0 |xargs -0 ls -l {}

    • 删除为0的文件
      find . -type f -size 0c -print0 |xargs -0 ls -l {}

    CentOS Linux Server 会将许多系统运行的状态发邮件给管理员root用户,系统邮件存放在 /var/spool/mail/root 目录中,可以通过使用 mail 命令来查看邮件,但是时间长了,也会造成邮件过多,如何使用 Shell 命令来批量删除或者全部删除呢?

      方法一:使用mail命令,然后在 & 提示符下使用 d 命令(Delete),批量删除邮件,例如删除1~53邮件:

      # mail
      & d 1-53

      方法二:删除全部系统邮件

      # > /var/spool/mail/root or cat /dev/null > /var/spool/mail/root

      或者

      # echo “d *” |mail -N

    有時候系統會提示收到郵件,通常是一些系統錯誤的通知,看完確認沒問題就可以刪了。

    通知長得像這樣:
    You have new mail in /var/spool/mail/root
    刪除的方法很簡單,用以下兩種指令擇一即可。

    cp /dev/null /var/spool/mail/root

    /var/spool/mail/root
    這樣就會清空root的mail。