Friday, August 15, 2014

预加载 JavaScript

在项目里有需要预加载 JavaScript 文件,按照经验就使用
(new Image()).src = url;

不过发现 Chrome 里,Image 请求会添加特殊的 Accept 头,导致后续实际创建 script tag 的时候浏览器会重新发送 Http 请求。

尝试搜索了一下,发现有人创建 object 对象,设置 data 来解决这个问题,不过,如何得知 onload 呢?

有待继续研究。

Tuesday, November 29, 2011

使用nginx记日志

使用nginx记日志

做web服务和应用的时候,很多场景下需要记录日志。
如 访问日志,性能分析日志,打点日志,数据统计日志等。

假设有以下主机设置
<code>
server {
listen 80;
server_name abc.cc;
root /etc/www/abc;

access_log /var/log/www/abc/access.log;
location / {
index index.htm index.htm;
}
}
</code>

默认情况下,access_log 会使用 combined 的配置来记录访问日志
<code>
log_format combined '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"';
</code>

通常这样就足够了。

如果是为了更加方便的日志分析,通常我们会使用特殊字符(如 ^A) 来作为日志字段的分隔符,
这样无论是过滤还是排序都会十分方便。甚至可以直接导入 mysql/hive 中,使用强大的 sql 来做查询分析。

为了排版方便,所有特殊字符都使用了展开的写法,请自行替换 ^A 为 ctrl+v,ctrl+a (nginx 日志格式不支持 \1 的写法)。

自定义日志格式:
<code>
server {
listen 80;
server_name abc.cc;
root /etc/www/abc;

# 更多日志可用字段(基本上都是 nginx 的变量),见
# http://wiki.nginx.org/NginxHttpLogModule#log_format
# http://wiki.nginx.org/NginxHttpUpstreamModule#Variables
# http://wiki.nginx.org/NginxHttpCoreModule#Variables
log_format abc "$remote_addr^A$remote_user^A$time_local^A$request_method^A$uri^A$args^A$server_protocol"
"^A$status^A$body_bytes_sent^A$http_referer"
"^A$http_user_agent";
access_log /var/log/www/abc/access.log abc;
location / {
index index.htm index.htm;
}
}
</code>

当把日志使用 ^A 分割以后,后续就可以使用 sort 和 grep 之类工具对特定url做分析了,
比如统计各url请求量倒排取前50个

<code>
awk -F^A '{print $5}' /var/log/www/abc/access.log | sort | uniq -c | sort -nr | head -50
</code>

有时候可能想对记录的字段做一些处理,比如 $arg_q 可能是搜索关键词,记录的时候如果 unescape 一下,
会更方便分析,存储上也会更小,
那么可以使用 NginxHttpSetMiscModule 模块提供的指令( http://wiki.nginx.org/NginxHttpSetMiscModule#set_unescape_uri )实现:

<code>
set_unescape_uri $q $arg_q;

log_format abc "$q";
</code>

有时候,我们需要对字段做 hash 转换,可以使用 HttpMapModule 提供的功能(http://wiki.nginx.org/HttpMapModule)

<code>
# 需要放到 http 里面,不能放到 server 里 :)
# 根据 url 地址计算分类,便于后续统计
# 具体根据需求做变换就好了
# 第一列是匹配规则,后面的是赋值 ~ 开头的匹配规则是正则
map $uri $typ {
default -;

~/login user;
~/my user;
~/static static;
}

log_format abc "$typ^A$uri";
</code>

如果使用 nginx 比较多,可能会尝试使用 if ,建议不要使用,因为nginx的if比较让人混乱。
如果有更多复杂的字段处理需求,可以使用 ngx_lua (http://wiki.nginx.org/HttpLuaModule)。
ngx_lua 里面操作 nginx 变量

<code>
# 实现上面 map 类似的功能
# 用法详见 http://wiki.nginx.org/HttpLuaModule#set_by_lua
# lua 语法见 http://www.lua.org/manual/5.1/manual.html#2.4
set_by_lua $typ "
local uri = ngx.var.uri
local _m = string.match
local v = '-'
if _m(uri, '^/login') then
v = 'user'
elseif _m(uri, '^/my') then
v = 'user'
elseif _m(uri, '^/static') then
v = 'static'
end

return v
";
</code>

某些情况下,可能我们的字段处理需要查询缓存(如redis)、数据库(如mysql)等,
这些都是可以使用 ngx_openresty 高效完成的(http://openresty.org/)。
这些功能就不在这一篇详细描述了,后续篇章会补充这些功能。
再描述一些复杂的日志记录功能吧。

有时候我们希望根据请求,来判断是否需要记录这一条日志。
在web的访问日志中这种需求比较少,但是独立的日志收集服务器一般有这样的需求的。
比如我需要判定,请求参数 arg_id 必须存在且为数字的时候我才记录日志,可以这样实现

<code>
server {
listen 80;
server_name abc.cc;
root /etc/www/abc;

log_format abc "$msec^A$args^A$q^A$ie^A$oe^A$ref"
"^A$http_user_agent";
access_log off;
location / {
# 专门记日志的服务,对非合法请求,直接断开连接 或者根据需求302到自己的站点
# 但是这种302一般不会被用户看到 可以综合考虑做法
# 444 的意义见 http://wiki.nginx.org/HttpRewriteModule#return
return 444;
}
location = /i-log {
internal;

set_unescape_uri $q $arg_q;
set_unescape_uri $ie $arg_ie;
set_unescape_uri $oe $arg_oe;
set_unescape_uri $ref $arg_ref;

# 这个很重要,否则不会记录的
log_subrequest on;

access_log /var/log/www/abc/access.log abc;
# 这个指令需要 HttpEchoModule (http://wiki.nginx.org/HttpEchoModule#echo) 的支持
# 因为这个地址只是为了辅助记录日志,所以不需要返回内容
echo '';
}
location = /1.gif {
default_type image/gif;
access_log off;

access_by_lua "
local q = ngx.var.arg_q
if q then
q = ngx.unescape_uri(q)
if q and #q > 0 then
ngx.location.capture('/i-log?' .. ngx.var.args)
end
end
";

# 这种请求一般不缓存
add_header Expires "Fri, 01 Jan 1980 00:00:00 GMT";
add_header Pragma "no-cache";
add_header Cache-Control "no-cache, max-age=0, must-revalidate";

# 一般独立记录日志的请求,都会返回一张 1x1 的空白gif图
empty_gif;
}
}
</code>

利用这个特性,我们甚至可以合并多个记录为1个http请求,在 ngx_lua 内再将多条记录拆分记录到日志文件
比如上例,我门可以添加一个字段 n 来标识有几条记录,并且给 q 之类的参数编号 q_1 .. q_n 。

<code>
# GET /1.gif?n=2&q_1=a&q_2=b&ie=gbk&oe=utf8&ref=
# 其他代码不变,只修改 1.gif 的 access_by_lua 为以下代码
local n = ngx.var.arg_n
if n then
n = tonumber(n)
if n > 0 then
local logs = {}

local prefix = string.format('/i-log?ie=%s&oe=%s&ref=%s&q=', ngx.var.arg_ie, ngx.var.arg_oe, ngx.var.arg_ref)
while n >= 1 do
-- 这里可以对 q_n 做进一步的校验,看是否需要记录下来
table.insert(logs, {prefix .. (ngx.var['arg_q_' .. n] or '')})
n = n - 1
end

-- 见 http://wiki.nginx.org/HttpLuaModule#ngx.location.capture_multi
ngx.location.capture_multi(logs)
end
end
</code>


如果请求量较大,一把需要添加写buffer,
方式为在每条 access_log 后面添加 buffer=32k 这样的设置(见 http://wiki.nginx.org/NginxHttpLogModule#access_log)
缓存的大小可以设置成 可以忍受丢失的记录数*每条记录的size

至此,各种记录功能都完成啦。
日志服务其他必要的功能,就是日志轮转了。

nginx 日志轮转的原理是

# 启动nginx收日志
# 启用cron任务
## 将日志文件move走 (文件名可以带上时间戳)
## 给 nginx master 进程发送 USR1 信号(nginx就会重新打开新的日志文件)
### 否则,日志会仍然记录到之前的日志文件中,虽然被 move 了
## cron 的频度可以根据日志大小调整,尽可能大些,能以天为单位就不要以半天为单位

具体实现可见 http://jk.aiwaly.com/wp/nginx-cut-log.html

以上操作中涉及较多 nginx 扩展模块,如果不想折腾,可以使用 ngx_openresty (http://openresty.org)
如果是淘宝系的同学,可以旺旺联系 定球 ,我们有现成的 rpm 可以使用:)

使用中有任何问题,欢迎发信到 kindy61 <at gmail> 或者 微博 @定球呀球

Tuesday, November 1, 2011

shell 下进行url编码解码

shell 下想进行简单的url编码、解码操作,可以使用 perl 提供的函数来进行

echo '测试' | perl -MURI::Escape -pe '$_ = uri_escape($_)'
echo '测试' | perl -MURI::Escape -pe '$_ = uri_escape($_)' | perl -MURI::Escape -pe '$_ = uri_unescape($_)'

:)

Thursday, October 27, 2011

nfs 网络共享基础设置

使用发行版内的 nfs 相关的包,涉及到的配置文件,服务器端有 /etc/exports ,用于设置共享哪些目录,
客户端一般临时使用 mount 即可,如果需要长久使用 修改 /etc/fstab 加入到自动设置里面。

假设服务器的ip为 192.168.1.123 修改 /etc/exports ,在后面添加

/home/abc/share 192.168.1.0/16(ro,async) 192.168.0.0/16(ro,async)

然后确认 $ ps aux|grep nfs 是否启动了,一般使用 $ /etc/init.d/nfs status 来确认是否运行
使用 $ /etc/init.d/nfs start 来启动服务,
这样,所有ip段在 192.168.1.x 的用户都可以使用

sudo mount -t nfs 192.168.1.123:/home/abc/share ./abc-share

来映射这个目录

如果想以后每次自动挂上这个目录,在客户端的 /etc/fstab 文件的最后添加

192.168.1.123:/home/abc/share /home/cde/abc-share nfs ro,async 0 0

just enjoy it.

Saturday, May 7, 2011

vim 里把左右切分的窗口变成上下切分

a | b

a
-
b


^w + K

需要大写的 K(或者 J 可以试试) 。

同理 H, L 可以把窗口反过来。

Saturday, April 2, 2011

vim 的 sort 和系统的 sort

如果想将 vim 内的若干行文本进行排序,有2种办法

:%!sort
:%sort

系统 sort 比较奇怪,貌似只支持使用空白字符和字母排序,遇到 * . 之类的都会忽略掉。偶尔也会觉得这样很恶心。
所以就用 vim 自带的 sort 吧。
等想排除非字母字符,再用系统的 sort 吧。


Tuesday, March 8, 2011

ngx_openresty系列之 ngx_lua vs. node.js

ngx_lua 是由 chaoslawful 和 agentzh 开发的用于 web 开发的 nginx 扩展,
其主要特点在于利用了 nginx 的非阻塞 IO 模型以及 lua VM 的灵活性。

node.js 是 ry 主导开发的基于强大高效的 v8 引擎,
提供了事件模型和各种基础设施的 web 开发平台,
其主要特点是内部各种 IO 操作是非阻塞的,为高并发提供了很好的基础。
同时,因为基于 js 语法,和 web 前端融合较紧密,
可以提供前后一致的编程体验(当然,客户端还比较难达到服务器端的爽)。

在传统的 php 编程中,当需要查询数据库时,当前的
apache 进程(或线程)(或 php-fpm 之类)在数据结果返回前一直处于等待状态,
如果大量的请求都在做数据库查询操作,那么服务器就没法处理更多请求。
因为 apache 能开启的进程(或线程)数是有限的(受内存限制)。

<code>
<?php
// 连接数据库时,进程是在等待的
$c = mysql_connect('mysql_host', 'user', '****');
mysql_select_db('my_database');

$query = 'SELECT col1 FROM my_table LIMIT 10';
// 查询时,进程是在等待的
$result = mysql_query($query);

while ($line = mysql_fetch_array($result, MYSQL_ASSOC)) {
    echo " * " . $line[0] . "\n";
}

mysql_free_result($result);
mysql_close($c);
?>
</code>

如上面的代码所示,在跟外部系统交互的时候,当前进程啥都没干,净等着了,
你还不能抱怨人家不干活,因为理由很充分:数据库忙着呢,我得等!
真的这样么?
我们看看 node.js 怎么做的。

<code>
// 仅仅给出部分代码,不能直接运行
// resp 是响应体对象

var c = new require('mysql').Client();
c.user = 'user';
c.password = '****';

// 开始连接数据库,同时注册了一个在连接成功后要执行的函数
// 注意,这时候 node.js 做了这件事情以后代码还在继续往下执行
c.connect(function (err, results) {
    if (err) {
        resp.end("ERROR: " + err.message);
        return;
    }

    // 这里发了一个数据库请求,并且注册了一个在请求完成后要
    // 执行的函数,注册完毕后就跟刚才一样干其他事情去了
    c.query(
        'SELECT col1 FROM my_table LIMIT 10',
        function (err, results, fields) {
            if (err) {
                resp.end("ERROR: " + err.message);
                return;
            }

            for (var i = 0, iM = results.length; i < iM; ++i) {
                resp.write(' * ' + results[i][0] + '\n');
            }

            resp.end();
            c.end();
        });
});
</code>

我们可以看到,node.js 对 IO 的做法是当要发生可能等待的事情时,
注册个函数在那里,然后继续做其他事情,当实际的数据到达或者事件完成时,
再调用之前注册的函数来处理。
整个 node.js 环境内漂浮着许多事件和函数,
在底层,有一些机制来保证这些事件的正确、准确触发。

在这种思路下,业务处理代码被切片,然后被注册到各种事件上面去,
这些由 node.js 统一管理,因此实现了非阻塞的处理。

对于 php 来说,一旦 apache 把控制权转交给 php 以后,
他们之间就很难转让控制权了,我们不可能把 php 代码切分到这样细致的地步,
因为即使切分了也没法注册给 apache ,而在 php 内部注册也是没有意义的:
一个 php 进程一般只处理一个客户端请求而已,在一个请求内添加事件的概念,
没法提升系统整体的并发能力。

node.js 还有一个很大的优势是 连接池。
在 php 里,连接可能仅仅是复用而已,连接池的意义应该不大。
而在 node.js 里,连接是可以在多个请求之间共享的,
只要 node.js 服务器不重启或关闭,那么这些连接便可以一直复用。

看到这里,你有没有激动或者兴奋呢?
是否要抛弃执着等待 IO 的 apache + php 这一对黄金搭档呢?
不过,我们稍等一下,如果为了非阻塞的特性,而要我人肉的拆分我的代码
成为很多函数(代码片段)然后注册到各种事件上去,会不会写起来很恶心?
或者,有没有从天上掉下来的什么东西,能够让我写像 php 那样从上到下的代码,
而又能够像 node.js 那样非阻塞呢?

ngx_lua 就是这样的东西。
那,ngx_lua 到底是神马东西呢?我们先看段代码。

<code>
upstream db {
    drizzle_server mysql_host:3306 protocol=mysql
                   dbname=my_database user=user password=****;
}

http {
    server {
        location = /i-mysql {
            internal;

            drizzle_query $echo_request_body;
            drizzle_pass db;

            rds_json on;
        }

        location /test {
            content_by_lua '
                local yajl = require("yajl")

                local sql = "SELECT col1 FROM my_table LIMIT 10"
                local res = ngx.location.capture("/i-mysql",
                    { method = ngx.HTTP_POST, body = sql })

                if res.status ~= 200 then
                    ngx.say("error")
                    ngx.exit()
                end

                local result = yajl.to_value(res.body)

                for i, v in ipairs(result) do
                    ngx.say(" * " .. v)
                end
            ';
        }
    }
}
</code>

这是神马东西!!!!!!
好吧,其实这是一段 nginx 配置,
同时也是一段业务逻辑处理代码。

这里的写法跟 php 是类似的,从上到下,
但是呢,它对待 IO 的态度跟 node.js 是一样的,
当开始 IO 操作的时候,它会暂停当前代码的执行并发起数据请求,
当请求完成后,恢复之前暂停的代码,并把结果返回。

ngx_lua 的模型是一个 nginx 进程内可以同时处理不限数量(几乎)的请求,
他们按照上面描述的逻辑执行。

你可能会说,
那为什么要用 lua 这个没听说过的东西来搞,
而不用 php 或者 js 搞呢?

刚才说了,当发起请求的时候,需要暂停代码的执行,
暂时只有 lua 运行时支持这个特性(或者有其他什么主流语言支持,赶快说来听听)。
并且 lua 里面创建的进程(其实是协程)非常轻量,占用内存非常少,可以让服务器同时处理更多请求。

这篇文章是个开头,
后续会更多的介绍 ngx_lua 的周边和现状,
以及更多的使用示例。



Thursday, February 10, 2011

下雪了

早晨迷迷蒙蒙的醒来,
发现下雪了,
虽不至若狂,却很是欣喜。

转又发现很多铲雪的声音和身影,
遂想,为何这会带来烦恼的雪,
会让我觉得欣喜呢?

或者是太久低迷的心情,
因为这雪而释放了。

或者是听到广播里太多的话语,
抱怨这没有雪的冬天太不像样,
现在终于下雪了,连我也感受到了这像样的冬天了
——没有雪的冬天是不完整的冬天。

早早的来到公司,
一个人静静的看窗外细碎的雪花飘舞,
无论是发呆还是遐想,
都是很不错的。

忽然想起,
19、20交际的时候,
有帮文人开始积极的探索改革,
期望能够帮助当权政府改善,
然而他们失败了,
看来即使所谓的头头想要改变,
也是困难的,
为什么呢,
可能是牵涉到的利益群体太多,
而这些利益群体又是极其重要和关键的,
比如人家有一切维护和保障权力的资格和能力。
人家反对,
当然很难做出什么实质性的改变了。

所以就导致人们出来抗议,
干脆我们重新洗牌,
总能碰到一手好牌吧。

也许社会就是这样,
就像一场牌局。
当前执政的人,就像我们的牌。
也许初抓到一首烂牌,
但只要运气好,技术好,
慢慢的也会翻势。

只是社会这场是永没有结束的牌局,
可以重新抓,只是永远打不完。

而所有的民众就是打牌的人,
随着打的越久,
也许技巧就越高,
大家只是在每一局里面不断的调整手里的牌,
保持一个良好的状态,
可是,却永远没法赢。

好牌放在手里只是一种感觉,
因为你既不会输,也不会赢。
你要做的也许只是陪着大家打牌。

雪还在下着,
心情却不如刚才那般明亮了。
何苦呢。

Saturday, October 9, 2010

jquery 事件处理研究(1)

jquery 事件绑定很好用,
不过处理事件冒泡、后续事件执行逻辑很是纠结。
总结已知的逻辑如下。


jquery 的事件提供以下方法处理相关逻辑:

1. ev.preventDefault -> 阻止浏览器绑定到当前 node 的默认行为,比如 a 链接的 click 事件默认会跳转
2. ev.stopPropagation -> 阻止冒泡,即当前 node 的 parentNode s 绑定的同类型事件不会被触发
3. ev.stopImmediatePropagation -> 阻止当前 node 同事件类型 后续函数的触发,会自动调用 ev.stopPropagation() ,
    比如给 #a 绑定了 5 个 click ,当第 2 个函数调用了 ev.stopImmediatePropagation() 以后,后面的 3 个函数都不会被调用,
    并且这个 click 事件也不会再冒泡了。
    如果只想阻止后续函数的触发而不阻止冒泡(假如有这需求呢),那么可以设置
        ev.isImmediatePropagationStopped = function () {return true;}; 即可。
4. return false -> 如果事件处理函数返回 false ,那么 jquery 会自动调用 ev.stopPropagation() 和 ev.preventDefault() ;
    但是后续函数会继续执行 :(

以上描述在正常的 .bind .click 等方法中正常,在 .live 和 .delegate 稍有不同

1. 在 .live 的事件处理函数中 return false ,行为不仅仅是上面描述的,还会产生类似 ev.stopImmediatePropagation() 的效果,
    即后续的 live 事件都不执行了;
2. 在 .live 的事件处理函数中想阻止后续函数的执行,只能 return false ;
    但是这样有个副作用就是 jquery 会自动调用 ev.stopPropagation() 和 ev.preventDefault() ,这个行为没法改变!!!!



纠结的事情啊
望同样纠结、研究过的一起探讨


参考:


Saturday, September 25, 2010

mac osx 上安装git

很久很久以前,我在 mac 上装 git,从 source 。
结果发现没法 make doc

因为他需要 xmlto 这个东西,
而这个东西需要能支持 --long-opt 的 getopt ,
从 http://software.frodo.looijaard.name/getopt/download.php 下载的东西编译不能通过,
经查是因为 getopt 的 Makefile 有错误导致。

文件 line.36 

CPPFLAGS=-DLIBCGETOPT=$(LIBCGETOPT) -DWITHOUT_GETTEXT=$(WITHOUT_GETTEXT) -DLOCALEDIR=\"$(localedir)\" -DNOT_UTIL_LINUX

的 -DWITH_GETTEXT 是错误,按照上面的修改即可。

可能大多数人都有个 gettext 所有没问题。

OK, 无论如何,解决了就好。





PS: 最终还是没能 git - make man 成功,下次再战。

Monday, September 20, 2010

压缩好东东 lzo

这个世界上总有太多的好东西等着我们去发掘。

晚上看 kindle 的资料,无意中翻开下载的 kindle src ,发现里面有个 lzo 名字比较有趣,
打开看看就更有兴趣了,遂 go 了一把,觉得是个好东西,可以拿来替换掉 gzip 了。


Wednesday, August 18, 2010

vim 中同时滚动水平分割窗口


vim 中可以水平分割窗口, :vs file2
如果想保持滚动其中一个窗口,另一个也跟着滚动,可以这么来:

在两个窗口执行 :set scb
然后滚动其中任何一个,另一个也会滚动。

完整写法是 scrollbind ,简写为 scb

取消方法是  :set noscb

Sunday, July 18, 2010

周末小记

这个周末,看了几部电影。
《阿飞正传》
《空气人偶》
《人在冏途》

完了感觉,很庆幸自己四肢健全,而且是个人。不愁吃喝,当然啦,只是不愁基础的而已,但已足够。
人最怕的就是对比,但是,对比最能看出效果来。所以,对比完了我觉得,我还是很幸福的。

忙碌庸庸了这辈子的大部分时光,总想着能够做些改变,参加百淘让我感觉有了希望。

拥抱变化,拥有激情

这已经无敌了。

觉得,自己很空,需要多些读写。

Wednesday, June 23, 2010

ngx_lua 终于好了

终于。

无敌的晓哲和春哥,你们太强大了。
ngx_lua 在两位大侠的手里搞定了。
示例如下,看看他强大的威力吧。

location /lua {
    content_by_lua '
        local num = tonumber(ngx.var.arg_num) or 0;
        ngx.echo("num is: ", num, "\\n");

        if (num > 0) then
            res = ngx.location.capture("/lua?num="..tostring(num - 1));
            ngx.echo("status=", res.status, " ");
            ngx.echo("body=", res.body, "\\n");
        else
            ngx.echo("end");
        end 
        ';  
}

$ curl -i localhost/lua?num=5
HTTP/1.1 200 OK
Server: nginx/0.8.40
Date: Wed, 23 Jun 2010 15:28:27 GMT
Content-Type: application/octet-stream
Transfer-Encoding: chunked
Connection: keep-alive

0? is: 5
status=200 body=num is: 4
status=200 body=num is: 3
status=200 body=num is: 2
status=200 body=num is: 1
status=200 body=num is: 0
end



强大吧。
可以计算 阶乘了。
呵呵。

Thursday, March 4, 2010

debian console 下显示中文

这是个老问题。


买了个古老的 imac,跑起来太慢,就给格了装 debian,
正常安装,没有 GUI。要显示中文,怎么办?
花费了大量的时间,最后无意间解决了。

安装 jfbterm 包,debian 自带 apt-get install jfbterm 即可。
装完执行 jfbterm 就可以启动了,以后再有中文、日文、韩文 等等 都可以正常显示了。

虽然我没明白为啥,
不过能显示就好。

至于输入,一般只有写东西的时候用到,
down 了一份 vimim.vim ,在 vim 里用。



关于 linux 下中文显示的问题,一直没弄明白,
按说字符映射到屏幕上是一定需要字库的,
为啥英文字符就可以显示,中文就不行呢。
或者,系统装完以后是带了字体的,只是带的是英文字体。

而且,奇怪的是通过 ssh 连接的 linux,只要终端支持,
也是可以正常使用中文的。

难道终端只是一个壳,负责传入与传出?

Friday, December 4, 2009

移动不小心解压出来的大量文件

某次,
下载到一个 .tar.bz2 文件,
直接 tar -jxf abc.tar.bz2

忽然发现目录下一下子多了很多很多文件,几百个。
不禁犯愁。最后解决如下:

$ mkdir _abc
$ mv $(tar -jtf abc.tar.bz2) _abc/

说明:
tar -jtf abc.tar.bz2 列出压缩包里面的所有文件,也就是刚才解压出来的文件列表,把这个列表传给 mv ,那这些文件就转移了。
:)

Tuesday, November 17, 2009

linux 下获取本机ip

获取本机 ip:

ifconfig |egrep -o 'inet addr:[0-9.]+'|egrep -o '[0-9.]+'


发现用 linux 越多,越来越多的知识点都糅合起来,
越来越得心应手~。

传统很强大,很好。

勤奋。。。。。。。

Tuesday, November 10, 2009

这个需求好变态

ps -eo pid,args,rss|grep apache|grep -v grep|awk '{print $3}'|perl -e
'$s = 0;while (<>){chomp;$s += $_;}print $s;'


作用:
计算 apache 总共用了多少内存,
单位是 kb。

Saturday, October 31, 2009

信用卡销卡风波

几个月前的某天:

有张某银行的信用卡,因为很久不用,偶然有个短信告诉我扣了100块的年费。
愤愤然,就打算给销了。

咨询以后得知只能电话操作,我就一个电话过去。

需要输入身份证和密码(电话操作的密码,不是取款密码),然后等待数分钟,有人接听。

R 您好,请问有什么能为你服务的?
L 我想销一张信用卡。
R 请问您为什么想销卡呢?
L 不想要了。
R ... 对信用卡的功能,作用,积分一顿猛说 ...
L 我不想要了,想销卡。
R 好的,为了验证您的身份,需要您回答一些办卡时的信息。
L 好。
R 请问您当时填写的家庭住址是哪里?
L 是 XX 吧?
R 不是。请问您当时填写的公司名称是什么?
L 是 XX 吧?(因为我也不记得了,这烂记性)
R 那您当时留的办公电话是?
L 抱歉啊,这个我不记得了。
R 好的,X先生,您的答案不能匹配我们的记录,很抱歉我不能为您办理销卡业务。
L 如果我挂失,需要这些信息么?我确实不记得那些信息了。
R 挂失是可以的。
L 挂失了还有年费么?
R 有的。
L 好吧。

挂断电话...
纠结........


今天:

前几天用那张信用卡取了2000块钱,
今天周末,打算还钱去。顺带一想,是不是可以把卡给销了。
遂找了附近的银行营业厅,里面有个不用拨号的电话,拿起来就打。

R 您好,请问有什么能为你服务的?
L 我想销一张信用卡。
R 请问您为什么想销卡呢?
L 不想要了。
R ... 对信用卡的功能,作用,积分一顿猛说 ...
L 我不想要了,想销卡。
R 好的,请问您想销的卡号后4位是什么?
L 2张都想销。
R 请您报一下卡号后4位好么?
L xxxx。另外一张没收到。(其实,另外一张是银行发短信说再办信卡有什么什么活动,我一想是不是可以借此机会证明我是卡片持有人,就答应办了,不过因为我没有修改账单地址,他给寄到以前的地址去了,我确实没收到)
R 好的,X先生,您好,我查询了一下您的账户,发现里面有未还款项,您必须结清里面的款项以后才可以办理销卡业务。
L 我不还是因为我之前打电话销卡,因为记不清我当时留的用户信息,所以不让我销,我不还款可以证明这张卡是我的,是否有营业厅可以还款,同时让我销掉这张卡?
R 您可以去信用卡办理中心,不过那里只提供身份证明,然后需要提交到我们信用卡客户管理中心,然后再处理您的销卡业务,整个流程下来需要10几个工作日。
L 需要这么久?
R 是的。
L 如果我一直不还卡里的钱会怎样?
R 到时候我们会有人上门收钱。
L 那我可不可以跟着收钱的人一起回去,还钱并且销卡?
R 不可以的,收钱的人是我们委托的。
L 我现在拿着这张卡,可以刷卡,取现,还钱,结果你说不能确认我的身份,不让我销卡,销卡必须确认我的开卡信息,我就是不记得了怎么办?
R 这个我也没有办法。
L (翻卡片发现10年3月就到期了) 那这张卡片到期以后我是不是就不用交年费了?
R 卡片到期后会自动续新卡,除非用户明确拒绝。
L 我要是没有那些信息呢?
R 那就没办法了。
L 要销卡是不是必须还清卡里的钱?
R 是的。
L 好吧,我知道了。再见。

挂了电话,我去了隔壁的自动存款机上把钱都还了。
我认栽。纠结的不行........

再会电话旁,打算用穷举法,去回答当时开卡时候的信息。
拨通以后又是输入身份证号和密码,然后有人听了,这次是个男的,前2次都是女的。

R 您好,请问有什么能为你服务的?
L 我想销一张信用卡。
R 好的,销卡以后您卡里的积分都没了。
L 我知道,我要销卡。
R 您要销哪张卡呢?
L 2张都要销。
R 好的。您卡里还有16元的余额...
L 我知道,不要了,我要销卡。
R 好的,请问您是否要保留您的用户信息呢?
L 有什么用?
R 您下次申请信用卡时验证会快一些。
L 谢谢,不用了,下次申请我再填。
R 好的。
... 同时,手机上来了2条短信,说我的2张信用卡已经停用。
L 我收到短信说信用卡停用,停用就是销卡么?
R 是的。
L 是以后就没有年费了?
R 是的。
L 好的,多谢。


挂电话。
有点莫名其妙。
这也太高效了,到底是为啥呢!!


路上我在想,
信用卡中心其实是不想让人销卡的,
所以就利用了我遗忘开卡信息这个理由,
千方百计的阻止我销卡。

不过,这个理由很不靠谱。
按照他们的说法是为了验证我的身份,
但是,
卡片使用时只需要卡片和密码即可验证身份,
在卡片欠费他们索费的时候应该只是凭借卡片关联的手机号码来确认身份:谁接电话跟谁要钱(管你谁呢,给钱就行),

如果他说销卡要那些开卡信息,那么平时的卡片使用过程中为什么不要求这么做?甚至连随机都没有。
那么他们所说的保护卡片安全 又在哪里呢?

就想我上面所说,
你允许别人使用卡片和密码随便使用,却不允许别人使用卡号和密码销卡,
这明显是一种极不公平的做法。
目的也很明显,
为了阻止用户销卡。

这样做只会降低用户的好感,
挫伤用户的心情。
于长久来看,
不是什么好事。

当然了,
电话员只是按照公司的规定办事,
我是不该改迁怒于他们的(好像我也没太过分,只是据理力争了一下子)。
问题在于这些规定的指定者。
销卡必须要开卡信息,
只能通过电话来操作。
这样的方式是否太专横了?

虽然说有信用卡中心可以做身份验证,但也只是提起申请,
而且效率极低,明显就是不想用户走这条路。

这跟国内的在线支付有些类似,
使用浏览器插件、控件名义上说为了用户安全,
其实是增加了用户的使用难度和复杂度。
paypal 并没有使用任何的浏览器插件、控件,
用户数量也并不比国内的支付产品少,
国外人也并不必国内人笨(黑客和诈骗应该也不少),
为啥人家就可以做好呢?


提供用户顺畅体验,
人们下次才会再来。
你老给人们设置障碍,
除非用户别无选择,
否则为啥要再来受阻受气一把?!

__end__

Thursday, October 29, 2009

心得

失败,失败,失败,首先大喊四声失败吧。


下面说心得:

01. 想去一个地方工作的话,弄清楚人家是做什么的,有什么主要业务,核心产品是什么很有必要的。
人家不会怕你烦的。


02. 做技术的人年轻的时候要深入的了解与掌握自己手头上的工具。所谓了解是指明白其工作原理,
虽然你会说,我又不做这个!但是了解其深层次的原理以后,会让你更好更有效的使用工具。
就好像写html的应该看看浏览器解析页面的机制。时间有限的时候就看看别人的分析,时间充裕
的时候就自己看浏览器实现代码(ff 和 webkit 都开源)。

掌握是什么呢?就是要熟悉工具的常用知识,比如关键字、常用函数、方法、类型等。虽然大多数
时候会有文档在手,不过熟练掌握的知识越多越好,所以,我们永远都不会闲的无聊。这就像练武
之人要时常练习一样,日久生疏。你每天都用的东西,总不能每天都需要翻帮助吧。每次翻出来,
删掉自己重写一遍,如此几次,慢慢会记住的,不可以过于依赖文档。

掌握是我薄弱的地方,以后会多加练习。


03. 多沟通,很多想法憋在肚子里烂掉了自己都不知道,说出来。
有时候有些话一出口,会自然带出很多你意想不到的东西来(当然,也有可能是不好的东西,稍微慎重一些)。


04. 身边常备纸笔熊。
纸笔拿来记录及草稿,
熊拿来表达不满、困惑和纠结——效果应该跟人差不多,好处是保护了秘密、朋友和自己。


--end--