Author: qingbo

  • grep: writing output: Broken pipe in iTerm2

    前天用 iTerm2,在执行一个 grep "xxx" filename | head (filename 这个文件应该相当大,grep 到的内容也应该有很多)这样的命令时,遇到大量如下错误输出:

    grep: writing output: Broken pipe

    而在 Mac 自带的 Terminal.app 里面执行完全一样的命令,不会有任何错误。用 which 查看,使用的确实是同一个 grep 命令,同一个 head 命令。再仔细观察,发现其实 iTerm 里面,命令也输出了正确的结果,那后面的这些错误信息应该是输出到 stderr 的。把命令改成

    grep "xxx" filename 2>errors | head
    

    确实,错误信息都跑到 errors 文件里了。这时又发现,在 Terminal.app 里命令在输出10行之后立即结束执行,而在 iTerm 里则取决于这个文件有多大,grep 出来的内容有多少行,它就会执行相应长的时间。网上看到有人说这是 head 取得10行后立即退出,这个 pipe 的读端就没了,grep 继续往 pipe 写,于是 – broken pipe, 只要将错误定向到 /dev/null, 忽略即可。可是我经常用 grep 来在特别大的日志文件里找东西,进行下一步分析前,就先用 head 看看 grep 的正则表达式写的对不对。每次 grep 都不管 head 只读少数行这个现实,一直执行到读完整个文件,太浪费时间和资源了。

    为什么在 Terminal 里,grep 会在 head 退出之后马上退出呢?当进程往一个 broken pipe 写东西的时候,会收到一个 SIGPIPE 信号,导致它退出。这时就觉得,肯定是 iTerm2 做了什么手脚,导致 SIGPIPE 这个信号没有被 grep 收到。

    用一个 dtrace 命令来看系统里信号的发送接收情况 (参考 dtrace oneliners):

    sudo dtrace -qn 'proc:::signal-send { printf("%s (PID=%d) sent signal %d to PID %d\n", execname, pid, arg1, args[1]->pr_pid) }
    proc:::signal-handle { printf("%s (PID=%d) was sent signal %d\n", execname, pid, arg0)}'
    

    在Terminal.app 里执行上面的命令,可以跟踪到:

    grep (PID=3524) sent signal 336414016 to PID 3524
    grep (PID=3524) was sent signal 13

    而在 iTerm 里执行则什么都没有(应该只能看见时间同步服务 ntpd 不停接收信号)。从上面也看到,信号其实是 grep 自己发给自己的,13 就是 SIGPIPE。我不了解 Unix 编程,猜想收到 SIGPIPE 退出这个应该是 libc 这样底层的库已经定义的行为吧。

    找到 iTerm2 的源代码,竟然轻易在它的 main.m 中找到了可疑代码:

    int main(int argc, const char *argv[])
    {
        signal(SIGPIPE, SIG_IGN);
        sigset_t signals;
        sigemptyset(&signals);
        sigaddset(&signals, SIGPIPE);
        sigprocmask(SIG_BLOCK, &signals, NULL);
    
        return NSApplicationMain(argc, argv);
    }
    

    一开始我只注意到第一行,signal(SIGPIPE, SIG_IGN); 即在收到 SIGPIPE 信号时忽略,但是注释掉之后发现和原来一样的行为 (如果只是 SIG_IGN, dtrace 应该能跟踪到发送)。接着注意到下面几行也是处理 SIGPIPE 信号的,把 SIGPIPE 完全 block 掉!至少 sigprocmask 这个函数是对子进程有作用的,因为在 iTerm2 里执行 grep,grep 就是 iTerm2 的子进程(具体关系是 iTerm2 – login – bash – grep,可以安装个 pstree 查看)。

    真相大白,果然把相关代码全部注释掉之后,用 XCode 自己 build 了一个,这个问题解决掉了。git blame main.m,发现这段代码是 2011-10-31 在 474cd19a972cea6a0d34f552a8a7ecaec514f3f9 这个 commit 加入的。所以在 iTerm2 下载列表里,使用 20111020 那个 build 应该没这个问题,而我用的是新一点的 20111219.

    在 google code 上创建了一个 issue, George Nachman 很快 fix 了这个问题。显然我的改法太简单粗暴,具体修改见 commit b0a6289bc0. 没想到竟然之前有人汇报的一个 issue 也是这个 bug 引起的,作者在此 issue 中上传了一个最新的 build 版本,大家可以使用。

  • 李笑来《把时间当作朋友》

    把时间当作朋友:运用心智获得解放李笑来. 国内很少有人像这样认真写好书了!

    在2012来临前把这本书读完了,收获比我想象中大得多(这本书是我买一本数学书时顺便一起买下的),值得多看几遍。这本书大致是关于时间,心智,思考,学习,坚持的探讨和思考,也有关于成功的定义,以及介绍达到成功目的的一些必要途径,不过当然不是市面上流行的成功学书籍。

    关于时间管理,David Allen 那本著名的 Getting Things Done 我也看了,看到一半就觉得好像作者在反复重复本来很简单的一些事,就好像当年学政治一样,看不下去了,也许是我不够有耐心吧。书中介绍的方法基本了解了,但是对我的工作学习似乎没有什么帮助,该拖延的事我还是拖延。我觉得方法这东西,每个人都应该有自己的一套,别人的好方法对自己并不一定有用。李笑来这本书虽然名字“把时间当作朋友”听起来就是一本时间管理的书,实际上它并不是教你时间管理的方法,而是在整个过程中告诉读者思考、反省、心智的重要性。

    记得中学的时候成绩好,好多同学老问我学习方法。我比较烦这样的人,就说我也没有什么方法。其实这是实话,突然被问到,我却是总结不出自己有什么方法。我不怕泄露自己的方法“给竞争对手做培训”,而是即使我公开自己的方法对任何人都没有帮助,还是不要浪费口舌了。这些人的关键是他们没有意识到高考前剩余时间的流逝,没有意识到学好这些课程的重要性,没有下决心要精心学习。现在大家都上过大学了,回头看看——高中的那些东西有大学一个学期的多吗?需要什么奇技淫巧才能学会吗……

    我曾经在一段无聊的时间里,早上起来,在电脑上安装我喜欢的游戏,打到晚上。那时感觉到自己一天什么事情都没有做,太堕落了,把游戏删掉。第二天早上又下载这个游戏重新安装继续玩,如此重复,越来越懊恼却没法改变。我觉得我的心智就比较弱,也许应该仔细想想,我已经到了什么年龄,财富、知识却少得可怜,我还有多少时间可以学习以及积累财富。

    不知道以后再有这样无聊的时候,由于读了这本书对我有没有帮助。不过在读它的过程里我就已经在思考很多以前没有想过的问题,看到很多让我感慨的地方,仔细记下了笔记。不过到最后才看到李敖读书的方法,其中一点是不要躺着读,不过这本书我就是躺着读的,只是遇到精彩的部分偶尔起来记一下。当然我不舍得像他那样把书分尸了。以后要坐着读书(尤其是纸质),这样有什么想法可以随时记下。我有个 Book Stand 帮忙。

    思考有很多方向,《把时间当作朋友》基本是教你用一种积极向上的态度思考。我曾有几段时间也大量思考,但是很悲观,把自己想到死胡同里,甚至有自杀的念头,多亏我想到我还有父母兄弟。自杀的念头多半实现不了,所以我们还得在这个世界上生存,积极的态度会有帮助的。


    最后摘录一些书中有意思的地方:

    1. 李笑来对某搜索引擎用低劣手段疯狂敛财很不满(105页括号中内容)。我相信百度因为钱去干扰 organic results 只是失败者的谣言而已,但是它的付费广告确实没有底线,或者说没有控制住底线。
    2. 关于马克思和他的幻想,请看130页。这么荒谬的幻想,竟然被人利用愚弄了这么多的人口,这个事实更荒谬!209页——“亚当斯密用一生奠定了现代经济学的理论基础,而另外一个哲学家终其一生写了无数著作,引发的却是人类史上最大规模的、最失败的社会实验”。
    3. 24页——“五笔输入法只不过是阶段性妥协的过渡产品,早晚会彻底消亡。”我最初就是学五笔打字的,我相信这一点,很庆幸自己比较早地回到拼音了。
    4. 160页,有些人希望借助他人的力量,他越是渺小,越是衬得他的欲望无比强烈,一个特征就是日程生活中他们经常有意无意地用亲密的方式体积大家仰望的人物。“李开复”叫“开复”,甚至“俞敏洪”叫“小俞”。

    书中提到的其它一些书:

    1. Knowledge and Decision
    2. The Tipping Point
    3. Mean Genes
    4. 少有人走的路
    5. 女心理师
    6. 奇特的一生
  • JVM 的 Client Mode 与 Server Mode

    目前正在读“深入理解 Java 虚拟机 – JVM 高级特性与最佳实践”,这本书确实是国内少见的好书之一,虽然个人感觉也有一些不恰当的地方。例如第3章介绍 GC 策略时,一直没有简单解释一下”新生代 (Young generation)” 和”老年代 (Tenured generation)” 这两个概念。我也是在这书中才发现 HotSpot VM 有两个模式 – Server Mode 与 Client Mode,作者也没有介绍。也许是因为这些话题比较初级吧。

    关于这两个模式的区别,这个 FAQ 里有介绍。简单地说,Client Mode 启动快,Server Mode 整体性能好。它们使用了不同的 JIT 编译器,Server VM 使用的那一个对代码做了更加多的优化。一般来说,像 Tomcat 这样的 Servlet container 需要长时间运行,启动速度相对来说不是那么的敏感,适合运行在 Server VM 里。而 GUI 程序对启动速度要求比较高,所以使用 Client VM 较好。

    它还提到 “Some of the other differences include the compilation policy,heap defaults, and inlining policy.” 当然按“深入理解 Java 虚拟机” 书中65页的表格,它们使用的 GC 策略也不一样。

    如何指定使用哪个 VM 呢?启动的时候指定 -client 或者 -server 参数即可。如果不写参数默认是哪个?官方说法是自动探测 “server class”. 该网页介绍,如果当前机器有两个或以上 CPU,并且有2GB以上内存,那么就认为这个机器是 server-class machine, 默认就会运行 Server VM. 说实话,这个 server class 的标准还挺低的,现在大多数个人笔记本电脑也都达到 server class 的要求了!

    如何知道某个 VM 进程在哪个模式运行?有几种办法。第一种是在程序自己里面输出:

    public class VMMode {
        public static void main(String[] args) throws InterruptedException {
            System.out.println(System.getProperty("java.vm.name"));
        }
    }
    

    分别尝试不同的命令行参数:

    $ java -client VMMode
    Java HotSpot(TM) Client VM
    $ java -server VMMode 
    Java HotSpot(TM) Server VM
    $ java VMMode 
    Java HotSpot(TM) Client VM
    

    刚才说到大多数个人电脑都达到 server class 标准了,可怜我的破电脑还是单核,1G内存 🙂 所以默认是 Client VM.

    第二种办法是对于一个运行中的 VM 进程,可以通过 jps 先获取其 pid,然后用 jinfo 获取系统属性:

    jinfo -sysprops 20417
    

    结果中有一行是

    java.vm.name = Java HotSpot(TM) Client VM
    

    也可以通过图形界面的工具,例如 JDK 自带的 jvisualvm 来看这个属性。

  • 让 Greasemonkey 脚本同时支持 Firefox 和 Chrome

    Greasemonkey 最初只是 Firefox 的一个扩展,不过流行之后,很快被其它的浏览器以不同形式采纳。IE 我不喜欢,此文就不关心它了。剩下的市场份额较高的是 Chrome 和 Firefox, 本文就简单讨论一下如何写出同时支持这两种浏览器的 user script (所谓“跨浏览器”).

    最早的时候也是热心用户给 Chrome 写了插件让它支持 user scripts, 但是现在 Chrome 不再另外需要插件就可以支持了。它的处理方式是每次安装 user script 的时候,自动把它转换成一个扩展!刚开始在 Chrome 上调试脚本的时候,我还尝试在磁盘上找到它存储脚本的目录——在 Firefox 里我都是直接编辑脚本,保存,刷新页面马上看到效果,简单粗暴。肯定有更简单的调试方式,只是我不知道。

    看看 Chrome 的官方文档怎么介绍的:

    Chromium does not support @require, @resource, unsafeWindow, GM_registerMenuCommand, GM_setValue, or GM_getValue.

    GM_xmlhttpRequest is same-origin only.

    这个显然有点过时。根据最近被完成的这个 issue,现在 GM_xmlhttpRequest 已经可以跨域请求了。

    关键的一点,Chrome 不支持 @require 的写法,这可是个很方便的功能啊。我对 jQuery 相对熟悉一点,几乎每个脚本里都会用这个命令把 jQuery 引入。这里有个例子介绍怎么解决这个问题。再稍稍加工一下,就得到一个跨浏览器的引入多个外部 JavaScript 的方案:

    跨浏览器 @require

    // ==UserScript==
    // @name           ???
    // @namespace      http://your.tld/
    // ==/UserScript==
    
    var scripts = [
      '//cdnjs.cloudflare.com/ajax/libs/jquery/1.7/jquery.min.js',
      '//www.readability.com/embed.js'
    ];
    
    var numScripts = scripts.length, loadedScripts = 0;
    
    GM_addStyle('CSS styles goes here');
    
    function main() {
      jQuery.noConflict(); // if window.$ has been used by other libs
      // ...
    }
    
    var i, protocol = document.location.protocol;
    for (i = 0; i < numScripts; i++) {
      var script = document.createElement("script");
      script.setAttribute("src", protocol + scripts[i]);
      script.addEventListener('load', function() {
          loadedScripts += 1;
          if (loadedScripts < numScripts) {
            return;
          }
          var script = document.createElement("script");
          script.textContent = "(" + main.toString() + ")();";
          document.body.appendChild(script);
        }, false);
      document.body.appendChild(script);
      console.log(script);
    }
    

    在这个方案里,我把主要的逻辑都放在 main 函数里。需要搞清楚的是,main 不会在这个扩展脚本的 scope 里运行!它实际上是作为页面里内嵌的一段 JavaScript 代码被执行了,所以不要在里面引用任何所谓“全局变量”(不过可以引用你所确定知道的页面 window 对象的属性)。所以它不能调用 GM_addStyle, 于是我放在 main 外面。需要 Ajax 的话,也只能使用普通的 XMLHttpRequest 对象,也就不能进行跨域数据请求了,这在某些脚本里可能无法忍受。

    iframe

    在 Firefox 的 Greasemonkey 里,如果你在文件头用 @include 声明一个 URL 格式,只要符合要求,不管是正常网页还是 iframe,脚本都会执行。但是 Chrome 不会在 iframe 里执行它!

    当然这个问题也有解决办法。比如 Gmail 最上面的菜单栏是在一个 iframe 里的,用这种方式获取:

    window.frames['canvas_frame'].contentDocument.getElementById('gbz')
    

    注意这里用的是 contentDocument. Chrome 不支持 contentWindow.document.

    其它问题

    我还遇到一个小问题是在使用 GM_xmlhttpRequest 设定 User-Agent 的时候。Chrome 报错:

    Refused to set unsafe header “User-agent”

    想了解更多请看我最近写的两个实用的 user scripts:

    这两个脚本都很简短,并且同时支持 Firefox 和 Chrome.

  • Google Reader 与 Kindle

    今天写了一个 Greasemonkey 脚本 – Google Reader Readability (点击安装). 该脚本同时支持 Firefox 和 Chrome. 效果如下,在每篇文章下面的工具栏添加一个新模块:

    Google Reader Readability

    Readability 是专注于阅读的一家网站,最近刚推出了一系列产品,覆盖主要的一些便携设备,当然针对阅读的话必须有 Kindle 了。它的 publisher tool 给我们这样写博客的或者那些新闻网站提供一个小的 widget,点击即可在 readability.com 阅读,还有一个很好的功能是发送到 Kindle. 而我的这个插件就是基于 publisher tool 的 JavaScript 代码 - 幸好他们没有压缩这个 JS,让我比较容易搞定了。其原理就是对网页作简单的处理之后,邮件发送给 @free.kindle.com,然后 Amazon 就会在你连接 wifi 的时候把这些文章推送过来,免费。另外,Readability 有浏览器插件和 bookmarklet 可以在阅读任何网页的时候把它发给 Kindle.

    我现在 Kindle 里就有一个 Collection 叫 News & Articles,上网在 Google Reader 里看到比较长的好文章,就点一下这个按钮。定期 Turn on Wireless, 内容下载下来先放到这个 collection 里免得混乱,看完后直接删除 (最好是在选中文章的时候按右方向键,在那个界面里删除)。在 Kindle 里看书眼睛舒服,遇到英文生词的话查起来也方便。

    其实把 Google Reader 与 Kindle 连接的产品不只这一个。比如:

    G:RSS-Web 仍然是个网页,不过相当于利用 Google Reader API 重新设计了,适合在 Kindle,Nook 上显示。

    greader2kindle 这个 python 项目很霸气,把你 Google Reader 里所有未读文章做成一本书推送到 Kindle 上!不过我没有尝试,因为我不需要在 Kindle 上看那么多东西。

    klip.me 更加强大,它可以定期把文章集合推送到 Kindle 上,不过不用你去折腾 python 了。同时它也提供把单个网页发送到 Kindle 的插件

    Readability 有个问题就是它没有仔细考虑跳转的事。Google Reader 里好多 Feed 都是用 feedburner 服务的,结果就是转化的文章开头就显示来自 feedproxy.google.com, 而 readability 账户里的 reading list 前面也全都是 feedburner 的 favicon.

  • Dive Into * 作者 Mark Pilgrim 网上失踪 – 410 Gone

    Mark Pilgrim 是 Dive Into … 系列编程书籍的作者,比较出名的是 Dive Into Python. 我最早接触他的作品是 Universal Feed Parser 中的 chardet library,后来还由于看见他网站的字体很特别,自己也尝试了一下。多产的人就是这样,有时候没有意识,突然有一天发现自己在用很多他做的东西。这只是他的贡献的一小部分,他把许多书都做成了网站让人免费阅读,比如 diveintopython.org, diveintopython3.org 等等。甚至他的 blog 名字也叫 Dive Into Mark. 下面是 Wikipedia 对他的简单介绍:

    Mark Pilgrim is a software developer, writer, and advocate of free software. He authors a popular blog, and has written several books including Dive into Python, a guide to the Python programming language published under the GNU Free Documentation License. Formerly an accessibility architect in the IBM Emerging Technologies Group, he started working at Google in March 2007.

    前阵子我想看 Dive Into Python 这本书,但是发现网站返回 410 错误代码。当时以为是临时性的服务器问题没有在意,不过知道现在仍然无法访问,包括他所有的其它网站。在网上搜寻一番,原来在10月4日,人们就发现不仅他的所有网站都是 410: Gone,他的 GitHub, Google+, Reddit, Twitter 账户都已经删除,而且给他发电子邮件会被退回!详情见 “Searching For Mark Pilgrim“. 此文作者 Eric Meyer 还引用了 Mark 自己在03年写的一句:

    “Embracing HTTP error code 410 means embracing the impermanence of all things.”
    —Mark Pilgrim, March 27, 2003 (diveintomark.com)

    其实我早该想到,服务器出了问题的话,比如文件不小心损失,应该是返回 404 的。410 这个代码一般是人工设定。Jason Scott 在 twitter 上发了两条消息:

    Mark Pilgrim is alive/annoyed we called the police. Please stand down and give the man privacy and space, and thanks everyone for caring.

    The communication was specifically verified, it was him, and that’s that. That was the single hardest decision I’ve had to make this year.

    很显然 Mark 的网上失踪受到很多人的关注,有人甚至报警了(这让他很烦),不过他看起来没出什么事。不知道 Mark 生活中遇到了什么问题,还是已看破了互联网,他把自己网上主要的账户都删掉,并且花了心思把自己网站的错误码设置成 410, 然后从网上失踪了。难道这个日期也是精心选择的?4th October. 这只是猜测了,这种用法好像是英国的。(11月7日更新 – 刚发现 Mark Pilgrim 在书中提到自己是 philosophy major)


    很多人想起 Ruby 社区奇才 why the lucky stiff 的 “infosuicide”,跟 Mark 这次的做法如出一辙。豆瓣上还有一篇怀念的帖子,里面提到 _why 在删除他 twitter 账户前一天说了一句:

    “programming is rather thankless. u see your works become replaced by superior ones in a year. unable to run at all in a few more.”

    并提到有人猜测归隐原因是因为他的作品 hpricotnokogiri 超越。我觉得也许这是一部分原因,但是这样的人不会因为这事儿作出这么大决定吧。想到当时我用 Ruby 正好还比较过这两个 library,最后选择了 nokogiri. 我记得比较的过程中就发现这两个项目较劲很厉害,看看现在还存在的这篇文章就能感受到当时的血雨腥风啊 (注意里面的一个已经不可访问的链接文本 “WHY FIGHTS BACK! HPRICOT IN PERFORMANCE BUSTING SHOCKER!!”)。


    不知道 Mark Pilgrim 是不是还在 Google 工作?有人抱怨他就这样把所有东西删掉然后消失有点不负责任(当然肯定是喜欢他的作品的),不过有人说:

    Mark Pilgrim doesn’t owe anybody a lifelong Internet presence. Be glad he shared so much of his work under open licenses.

    我们已经见惯了网上删贴。郭美美引起众怒要删自己的微博,小米、360 公关乌龙要删自己的微博(以上提到的赶紧删,删光也没人稀罕),甚至封别人的口、删别人的帖子已经成了新的产业让很多人先富起来了。但是看到这些有才华,对社会进步有实实在在贡献的人把倾注心血的作品毁掉并失踪,是多么让人惋惜!

    怀念归怀念,已经有人开始维护 Mark Pilgrim 的镜像网站了,比如 Dive Into *. 另外我们也该珍惜时间,争取也做点贡献吧。最近这个行业的损失可不少:

  • Ubuntu 11.04 安装 scim-googlepinyin

    以前用 Mac 的时候,抱怨 Mac 没有好用的中文输入法,现在搜狗和腾讯竞争激烈,Mac 用户不愁输入法了。现在又用 Linux 了,一直希望腾讯或者搜狗能够为 Linux 开发一款输入法可是迟迟不见踪影。前面写了一片 Ubuntu 安装 ibus-cloud-pinyin 的,不过后来还是感觉体验不太好,用回默认的 ibus 拼音了。

    今天写东西还是觉得中文输入很烦,于是试试安装这个 scim-googlepinyin 吧。发现过程也不是太难,关键是怎么让 scim 正常运作起来。

    $ sudo apt-get install scim scim-pinyin
    

    然后在 Language Support 里把 Keyboard input method system 选成 scim 重新登录就可以了。安装完成后 System Preferrences 里就会有 SCIM 的设置,把所有的都看一下大致知道怎么配置了。不过问题是在很多输入框里,候选词列表不跟随光标移动,比较难受。解决办法是修改 /etc/X11/xinit/xinput.d/scim,把 GTK_IM_MODULE 改成 scim. 我把 QT_IM_MODULE 也改了,不过好像没效果,QT 程序里还是不跟随光标。对我来说无所谓,我目前用到的唯一 QT 程序是 skype,并且它的输入框就那么小,不碍事。

    我也不知道是什么影响一个输入法的体验的,这个是我感觉最好的。


    安装了 scim 之后发现系统的中文字体很奇怪,包括某些网页,标点符号跑到了正中心,让人受不了。看了一下目录 /etc/fonts/conf.d/ 下面有几个更改日期为今天的配置文件,顺藤摸瓜,应该是安装 scim 的时候顺带安装了两个字体包。照下面的命令卸载掉即可,不会影响 scim 输入法使用:

    $ sudo apt-get remove ttf-arphic-uming ttf-arphic-ukai
    

    我不知道 apt 系统的依赖原理,不明白为啥安装 scim 的时候给我安装上,我卸载的时候却不管。

  • Kindle 不适合阅读结构化书籍

    Kindle 3 的软件在某次升级中,加入了 real page number 这么一个功能,似乎仅支持从 Amazon 购买的一部分书。我不知道这个功能到底有多大用处,Amazon 急于响应用户的要求。读书的过程中知道实际页码和知道百分比有什么区别吗?除非用这个功能是为了方便地在纸质书中找到对应的位置,去看一些在 Kindle 中排版错乱的文字、图表,或者 Kindle 中看不清的插图。

    在 Kindle 上看了各种各样的书之后,感觉它确实很难告诉读者,当前正在读的是什么地方。百分比、页码是不够的,纸质书是怎么做的?现在大多纸质书都会在页眉处标出章节,一般翻开书的任何地方,右边页眉标着这是第几章,左边页眉标着是第几节。这样读者困惑的时候,一抬头就知道自己看到哪儿了。我觉得 Kindle 最缺的就是这个,有时候不知道自己在什么地方,只好往前翻页,够痛苦。

    说到翻页,电子书的翻页也是够难受的。当然读书的过程中,大部分的操作都是一页一页往后翻。但是有时候比如你读小说,看到一个人的名字,明明刚十几页之前提到了却想不起来这是谁,翻页就比较痛苦。当然可以通过搜索定位,但是这样一般还得用书签记住当前位置,也挺麻烦的。

    最近看那个 Getting Things Done,作者也够唠叨的,一个概念翻来覆去很多次重复讲,可能是我没有耐心吧,有了上政治课的感觉。他那个几万英尺的说法,开头讲了一次,后半部分里又拿出来讲,其实当时我是比较想翻到开头去看看到底有什么区别的,但是由于 Kindle 做这个太麻烦,就懒得看这本书了。另一方面,我看了一下原版的纸质书(很久前买的,100大洋啊),章节层次是比较分明的,除了在页眉标明章节,更下面的层次就用大小字体、粗体、斜体依次标识。而 Kindle 版本的就只有两种层次,一种是很大的粗体,另一种就是斜体了,所以有时候不集中精力的话,看得云里雾里。

    目前来说,Kindle 最合适的还是看一些叙事性的小说。第一没有什么层次结构,第二不需要复杂的排版、插图、表格等。我老婆就在孜孜不倦地在这条路上实践。

    看来电子书还有很长的路要走。

  • Ubuntu 11.04 安装 ibus-cloud-pinyin

    首先安装必要的软件包(valac 默认版本不是 0.10 所以安装时必须指定版本号。subversion 是为了 checkout ibus-cloud-pinyin 的代码准备的):

    sudo apt-get install liblua5.1-0-dev liblua5.1-socket2 libsqlite3-dev libibus-dev libnotify-dev lua5.1 libgee-dev valac-0.10 sqlite3 subversion
    

    然后 check out ibus-cloud-pinyin 源代码,编译,安装:

    svn checkout http://ibus-cloud-pinyin.googlecode.com/svn/trunk/ ibus-cloud-pinyin
    cd ibus-cloud-pinyin/
    make
    sudo make install
    

    接下来重启 ibus. 通过命令:

    ps -ef | grep ibus-daemon
    

    找到 ibus 的进程号 kill 掉,然后通过菜单 System-> Preferences->Keyboard Input Methods 启动。现在点击输入法图标,应该多了个 Chinese – Cloud Pinyin,选择即可使用。我也不太清楚它使用的是哪个云输入法,但是词库、词频比默认的输入法好太多了。

    另外,想要开机启动 ibus,可以在 System->Preferences->Startup Applications 里添加 /usr/bin/ibus-daemon

  • 英文书籍阅读之难度

    最近读英文书比较多,感觉自己的阅读速度突飞猛进,心里很欢喜。不过几天前看《活着就为改变世界:史蒂夫•乔布斯传》中文版很快看到三分之一,开始转读英文版,一下就懵了,觉得满篇都是生词。

    高中时想找本完整的英文小说看,竟然在书摊上买了本英文版的《穆斯林的葬礼》!我现在想起来都觉得有点不可思议,不知道为什么翻译成英文又给卖到中国来。记得这本书也没看几页,因为基本上都是生词,查词典都查不过来,而且不是可以猜测意思跳过去的。文学作品里大多都有复杂的句子,还用很多修辞技巧,那时的我不可能接受。到现在,看这个 iCon Steve Jobs: The Greatest Second Act in the History of Business 仍然觉得有点难,读起来很慢。

    即使是跟自己不相干的偏专业性书籍,对我来说读起来也比文学作品容易。前阵子读了 Predictably Irrational, 没想到里面的英文会没有难度。主要原因就是作者 Dan Ariely 不是文学家,不常用一些对我们来说比较生僻的词汇。这本书的内容主要也是关于心理学、经济的,虽然有一些专业词汇,但是为数不多,可以接受,多见几遍就记住了。这两天正在读的是 Getting Things Done: The Art of Stress-Free Productivity,其实也是偏专业的一本。

    文学方面的书籍,即使是给小孩写的,比如 Alice’s Adventures in Wonderland,生词也是很多。一方面,作者为了不重复以防读者出现厌烦感,同一个意思变着法子换形容词,还有各种所谓 fancy word,就如有的街道不叫 street 叫 boulevard 一样。另一方面,文学作品描写生活、场景的很多,一涉及到这些就会出现大量我们从来没接触过的名词。不用细想,你往四周看看,家里有多少东西你不知道英文里叫什么?

    阅读除了学到书里的知识,对学习生词也是最好的方式了。尤其是一本书里反复出现的词汇,记忆效果非常好。这一点还是非文学类书籍做的最好,因为第一,技术性词汇会反复出现,不可避免;第二,作者不刻意追求形容词的不一致,所以很多形容词重复会用他偏好的那一个,对读者来说学习这个形容词就很有帮助。

    不过不管怎样,只要没有达到妨碍阅读的程度,都是学习英语的好工具,生词多少只是在一定程度上影响阅读速度吧。有了 Kindle 的帮助,现在查生词也越来越方便了。