Random Tech Thoughts

The title above is not random

Linux Initial Ramdisk 以及启动过程

推荐一篇 IBM developerworks 上的文章,Linux initial RAM disk (initrd) overview,很详细一篇介绍,包括了内核里哪些函数涉及到启动过程。另外 man initrd 也有相关的介绍。

不过文章的内容已经有点过时,内核启动过程调用的函数发生变化,默认执行的 initrd 里的程序也从 /linuxrc 变成 /init。另外现在 Linux 发行版大多用 cpio 格式的 initrd),这篇文章介绍的是 ext2 格式的。如何提取和创建 cpio 格式的 initrd 可以参考下面这篇文章 Debian Lenny 5.0.1 PXE initrd update,主要的命令如下:

# 提取
zcat ../initrd.gz | cpio -iv
# 创建
find . -print0 | cpio -0 -H newc -ov | gzip -c > ../initrd.gz

如果有 Linux 内核源码的话还可以参考 Documentation/initrd.txt,里面有启动过程的介绍和创建和提取 initrd 的说明,内容比 man initrd 更详细,不过也有一点过时。

推荐个 C 库 Sglib

SGLIB – A Simple Generic Library for C 完全用宏实现,只有一个头文件。提供了如下功能:

  • sorting arrays
  • manipulating linked lists
  • manipulating sorted linked lists
  • manipulating double linked lists
  • manipulating red-black trees
  • manipulating hashed containers

网页提供的下载链接地址不对,提供个sourceforge的下载地址。下载的 tarball 里有 sample 和 doc,看下就知道怎么用了。

一个我比较喜欢的特点是数据结构完全由用户自己定义,sglib 帮你生成操作数据结构的宏,函数声明以及定义。这样做的好处是不需要因为使用库而对数据结构做修改。相比 queue.h,我觉得 sglib 的更容易使用和理解,而且有更多功能。

Get the Current Module in Python

It’s sometimes useful to do introspection on the module itself you are writing. But python doesn’t provide any direct way to support this. In fact a PEP about this feature has been rejected.

A little google find a solution to this problem. Here’s the code

1
2
3
4
5
6
7
import sys
# get the current module's name
modname = globals()['__name__']
# get the module
module = sys.modules[modname]
# or more simply as suggested by E.T
module = sys.modules[__name__]

Reviewboard, PIL and Virtualenv

I created a separate no site-packages virtualenv directory, and use easy_install to install Reviewboard.

However, easy_install installs PIL version 1.1.7 which does not work with the latest stable Reviewboard version 1.0.5.1.

Using easy_install PIL==1.1.6 doesn’t work because of build error. The workaround is to manually download PIL and install it.

To make reviewboard work under virtualenv, additional steps are needed, which in fact are steps for Django application to work under virtualenv.

  • If you use mod_python and apache, this article maybe useful. This works for Reviewboard.
  • For mod_wsgi, look here.

更新 Zsh 的 Command Hash Table

zsh 下新装了一个软件,tab 补全时新装软件的命令不会出现。以前的解决办法是执行 export PATH=$PATH 让 zsh 去更新缓存。

今天在 Pylons 的 activate 脚本里看到了一条 builtin 命令 hash (man zshbuiltins),这条命令可以直接修改 command hash table。$PATH 路径下的内容发生变化时可以用 hash -r 来更新。

Screen & LD_LIBRARY_PATH

这篇 post 居然是在今年 1 月份的时候放到 draft 里,到现在才 publish……

因为用 intel 的编译器,所以设置了 LD_LIBRARY_PATH 这个环境变量,但是每次启动 screen 后这个环境本来都会被 unset。google 到的结果

screen 可执行文件是 setuid 的(为了 share session,debian 的 screen 安装时默认没有 setuid),glibc 对这样的可执行文件会把那些“危险”的环境变量去掉,所以出现了上面的情况

解决办法两个

  1. 把 setuid 位去掉,当然这样 screen 的 share session 就不能工作了,还好一般用不到
  2. 把 LD_LIBRARY_PATH 的设置放到 .zshrc/.bashrc 之类的文件里去,这样每次启动 shell 的时候自然会把这个环境变量读入的
if [ -z $LD_LIBRARY_PATH ]; then
    export $LD_LIBRARY_PATH=XXX
else
    export $LD_LIBRARY_PATH=$LD_LIBRARY_PATH:XXX
fi

LD_LIBRARY_PATH 这个环境变量设置起来还真的挺麻烦的,系统的库目录和自己的库目录下有同名不同版本的库的时候,不是自己的程序有问题就是系统的程序有问题。

Zsh + Screen

screen 提供多个 shell 来回切换是很方便,不过有时会忘记应该切换到哪个 window。如果可以根据执行的命令和当前目录来动态设置 window title 的话来回切换时就会可以方便的找到目标 window。其实 zsh-lovers 里就有说明。

screen 可以通过 echo 特殊的字符来设置 window 的 title,而 zsh 有两个特殊的函数 preexec 和 precmd,前者在用户输入命令按下回车但 zsh 还未执行命令前被调用,后者在 zsh 更新 prompt 前被调用(具体说明见 man zshmisc)。把 zsh 和 screen 的功能结合起来就可以在执行命令时把 screen window 的标题设置成当前执行的命令,而在 zsh 等待用户命令时,将 title 设置成当前目录

先贴 zsh 的相关配置,PS1 的配置不喜欢可以去掉。

autoload colors
colors

case $TERM in
    screen*)
        function sctitle() { print -Pn "\ek$1\e\\"}
        function precmd() { sctitle "%20..>$1%

有时命令或者当前目录很长,screen 的 status bar 宽度会不够,zsh 有内置的截短字符串的功能,用 %20..>$1%
startup_message off
# use visual bell
vbell off
# replace Ctrl-A by `
escape ``
# set a big scrolling buffer
defscrollback 5000
# Set the caption on the bottom line
caption always '%{= kg}[%{G}%H%{g}][%= %{= kw}%?%-Lw%?%{+b r}(%{y}%n %t%?(%u)%?%{r})%{= w}%?%+Lw%?%?%= %{g}][%{B} %d/%m %{W}%c %{g}]'
# %{= kG} first set default color (=), back ground black (k), foreground green (G)
# [%{G}%H%{g}] color bright green, host name (%H), color green
# [%= ...] padding (%=), window left to the current focus window if exists,
#      (current focus window with color yellow), window to the right of the
#      focus window
# [%{B} %m/%d %{W}%c %{g}] color bright blue, month/date (%m%d), color bright white,
#      current time(%c), color green

# open several terminals at startup
screen 5
screen 4
screen 3
screen 2
screen 1

因为我用 vim,而且我觉得切换 window 时要按数字键,所以我把 escape 设置成 back tick。这个配置最关键的就是 caption 了,忘记从哪里 copy 过来的了(用 hardstatus 的话 screen 的消息也是在 hardstatus 上显示,所以我喜欢用 caption)。我直接在配置文件里加了点注释,语法很恶心,我都看晕了。关于 caption/hardstatus 里的转义字符说明见 man screen 的 string escape 一节。

试试看吧,这个配置还是很炫而且也蛮实用的。

我也来推荐 Bpython

在光华上看到 Zellux 推荐的,bpython

bpython 对输入的代码有高亮显示,输入代码同时自动补全,不需要按 tab,调用函数时打完左括号文档就自动出现。

现在只是刚刚试了一下,印象不错。

有些 ipython 支持的功能 bpython 里没有,现在发现的是不支持直接执行 shell 命令。(文件名补全的话当前目录的要用 ./ 以后才会出来。)

Ch – 一个 C/C++ 解释器

动态语言很重要的一个功能就是支持交互式的开发,用惯了 Python 有时候非常希望 C 也能有一个解释器来用,尤其是忘了 C 的某些语法想写个简单的例子来测试的时候。

很久以前就搜过 C 的解释器,搜到过 Ch,不记得当时为什么没有试用过。今天下了个免费版本的用了下,很不错,支持 C90 和 C99 的主要功能,C++ 支持不完全(不过 C++ 我基本不关心)。

以前想要测试 C 的某个语法功能时会写个文件,int main 什么的搞一堆,然后用 tcc (Tiny C Compiler) 来测试。tcc 可以把 C 代码的编译和执行放在一步完成,执行 tcc -run foo.c 就可以看到效果了,还算方便。

用 Ch 就更方便了。ch 命令出来个交互式的 shell,输入 C 代码马上执行,调 printf 直接看到效果,输入变量就可以看到它的值(struct 的话可以看到每个成员的值),做点小的测试就不需要写 int main 之类的了。另外 ch 还有函数名补全。

Shell Like Data Processing in Python – Using Decorators

前面的文章展示了管道的好处,以及在 Python 程序中利用管道的思想。但是前面文章里的代码还有一点缺陷,看下面的 shell 脚本和 Python 代码的比较:

find logdir -name "access-log*" | \
xargs cat | \
grep '[^-]$' | \
awk '{ total += $NF } END { print total }'
1
2
3
lines = grep('[^-]$', cat(find('logdir', 'access-log*')))
col = (line.rsplit(None, 1)[1] for line in lines)
print sum(int(c) for c in col)

Python 中 find, cat, grep 的调用用一层层的括号嵌套起来进行调用,执行顺序是从最内部的括号开始,可读性没有 shell 脚本好。可不可能在 Python 脚本中用类似 shell 脚本里的语法来提高可读性?用运算符重载就可以做到了。最初的想法来自这里,这个例子用的方法是重载或运算符 “|”。新的 Python 代码如下,我把这样的代码称为 pipe syntax (抽取最后一列并求和的代码不变。)

1
lines = find('logdir', 'access-log*') | cat | grep('[^-]$')

用运算符重载的方法把一个函数放在管道中必须自己定义一个类,在 override 的 ror() 函数中完成实际的工作。每次都要定义一个类我觉得不够方便,因此我用 decorator 来进行简化。