一切都是巧合

TETware 做自动化测试框架,越来越觉得这玩意很差,至少是 ksh API 这部分,用我同事的话说,已经“out”了,在我手上改了不少,仍然不够好用。今天竟然发现一个记 log 的接口里面竟然会死循环,调查下去竟然是个 ksh93 的 bug,要不是这个接口写得这么烂,也许这个 bug 永远都见不到天日了。

废话扯完了,看看是什么 bug。

${parameter%pattern} 用来从 parameter 字符串中去掉 pattern 后缀,${parameter#pattern} 用来从 parameter 字符串中去掉 pattern 前缀,这两个经常用来取路径名中的目录和文件名。但是当 parameter 是个多行字符串并且 pattern 符合 “\n.*(.*).*” 模式时它们不干了:

$ cat ksh93bug
NL=$'\n'

PAT="$1"

A="Hello $NL$PAT"
echo "${A%$NL$PAT}"

A="$PAT$NL world"
echo "${A#$PAT$NL}"

$ ksh ksh93bug '()'
Hello
()
()
world

$ ksh ksh93bug 'a(b)c'
Hello
a(b)c
a(b)c
world

仅仅是 AT&T ksh93,包括最新版本都有这个问题,在 bash 和 public domain ksh 中没有问题:

$ bash ksh93bug '()'
Hello
world

$ bash ksh93bug 'a(b)c'
Hello
world

我们的例子是 out=$(mount) 接着 tet_infoline "$out"它就歇菜了,TETware 的 tetapi.ksh 在 tet_output 函数里面用 %% 在循环里面去处理多行文本,哪里想到后缀永远删除不掉,在我试图加 set -x 调试的时候迅速的将硬盘写满了:P

本想报告这个 bug,在 ksh93 主页 上没找到给谁报,懒得伺候了,先改 TETware 再说了。

工程师向往的地方又少了一个

获悉 Sun 公司 Kernel Networking 北京开发组全组被裁,当年我在这个组实习,转正后虽然去了别的组,无论工作还是私人关系都比较紧密,虽然知道是迟早的事,心里还是非常不好受。又悉其中三人转移到其他组,技术都很牛的三人,其中两个还是我最为佩服的,稍感欣慰。现下行业不景气,和尚多庙少,被裁的兄弟恐怕不太容易找到满意的工作,祝他们好运。

许个愿

牛年目标:

  1. 管理自己和老婆的健康,少宅多运动
  2. 工作上争取“出人头地”,令同事信服,老板放心
  3. 提高涵养,不斗气,对事对人能包容,做事要与年龄相称
  4. 拿到驾照
  5. 攒房子

joyus.net

忍不住还是把 joyus.net 注册了,过期半年了也没人要,怪可惜的。GoDaddy 还涨价了,还好汇率低。用这个 coupon 码 gdr0110m 可打 9 折,截至日期到这个月 22 号。

在 optparse 中用 -h 选项

Python 里 optparse 是一个很不错的命令行参数处理模块,不过当我想把 -h 用作指定 hostname 时发现默认的 -h 参数非常恼人,模块报告一个冲突,但是文档却没有记录如何解决这种问题。翻了源代码,找到解决办法:

方法一,初始化 OptionParser 的实例时指定 add_help_option=False,再自己添加一个 --help 选项:

parser = optparse.OptionParser(usage=usage, add_help_option=False)
parser.add_option('', '--help', action='help')

这样 -h 就空出来啦。

方法二,初始化 OptionParser 实例时指定 conflict_handler="resolve",然后就不用理会默认的 -h/--help 直接加自己的选项就行了,冲突时会只取用最后指定的选项。

parser = optparse.OptionParser(usage=usage, conflict_handler="resolve")

printf 的妙用

这天同事问了一个问题,shell 中如何重复显示指定数目的字符?例如显示 72 个等号(=)作为一个分界线。脑子里马上想到 perl 和 python 中这个实在是太容易了:

$ perl -e "print '=' x 72"
$ python -c "print '=' * 72"

但是 shell 中可没有这样的语法,想了半天,只想到一个利用 printf 命令结合 sed 的做法:

$ printf "%*s" 72 '' | sed 's/ /=/g'

"%*s" 这个 format string 后面的第一个参数是字符串显示宽度,第二个参数才是真正要显示的字符串(这里是空串),与 C 语言中的 printf 类似。

虽然这个 printf 有点妙,不过后面跟了个 sed 才算解决问题,作为一种脚本语言,Shell 有时让人觉得实在是太弱了。应该有更好的解法……

uptime

一晃已经在新公司 uptime 满 1 年了,甘苦自知。最近特别忙,一是新一版本发布在即,二是忙着给人擦屁股。让别人听自己的意见来干活,比埋头只干自己的可难多了。好在鄙人的意见都是具有建设性的,都有眼见的好处,目前没人找碴。难受的就是自己眼里很轻松的修改,别人那里成了累活,站在一旁看着强大的 vim 活生生被当成 notepad 用,要不是现在涵养有进步,一定会七窍生烟。

稍微闲一点,才发现 VPS 的 uptime 已经 96 天了,从上次迁移主机之后没有再出现任何问题。这个在 vpsvillage 购买的玩具般的 vps,已经使用了近半年啦。除了个 blog 和 wiki 外,最主要的用途乃是在公司使用 ssh 隧道做 socks5 代理,连接 MSN、Gtalk 和公司安全政策禁止访问的各类站点 :cool:,慢虽慢点,但是自由的感觉更重要。做个广告,还在用 bluehost,dreamhost 虚拟主机的、别再受那种鸟气了,玩玩 VPS 吧。

简单任务 2 - 计算并替换

用 iozone 跑出来的文件系统性能数据,格式示例:

# file-size     initial-read
1k 3029.832
2k 3010.015
4k 3223.711
8k 3303.412
16k 3488.440

简单任务:将 Nk 替换成 N*1024 的结果,m 和 g 依此类推。目的是要对处理之后的结果用 gnuplot 作图。

用正则表达式很容易匹配目标文本,但可惜不能直接计算。我的解法是先将整个文本替换成一个可执行的 shell 脚本 - 第一行插入 "cat << EOF",最后一行添 "EOF",中间的 k, m, g 替换成 "$((..))",然后用 shell 解释执行,利用 shell 进行计算。有点土,不过至少可以方便批量处理。

sed -e '1i\cat << EOF' \
-e 's/\b\([0-9]\+\)k\b/$((\1*1024))/g' \
-e 's/\b\([0-9]\+\)m\b/$((\1*1024*1024))/g' \
-e 's/\b\([0-9]\+\)g\b/$((\1*1024*1024*1024))/g' \
-e '$i\EOF' \
iozone-out.txt | bash

将 sed 表达式写到一个单独的 .sed 文件,可方便批量处理。再完善一点就先把 $ 和 ` 转个义。

for f in *.txt; do sed -f x.sed $f | bash > $f.new; done

谁有更好的解法?

简单任务 1 - 合并连续的空行

简单任务 - 将多个连续的空行合并成一个空行。来自一个实际问题:打印一个很长的 RFC 文档,希望能省一些纸张。

很久以前就遇到过这个问题,因为发现 sed 不能匹配 '\n',当时的解法是写了个 shell 脚本处理。Vim 可以用 '\n' 匹配换行符,解决方案是:

vim '+%s/^\n\+/\r/g' +x rfc.txt

考虑空行上可以有空白字符的话,还能再完善一点:

vim '+%s/^\(\s*\n\)\+/\r/g' +x rfc.txt

这是目前的“最佳应法”,欢迎提供更佳的解法。

特别鸣谢:刚开始缺少 '^' 怎么都不能成功,经老婆指正方才解决。你怎么也想不到,我老婆作为一个文科生,竟然能把 vim 使得出神入化,还在她们公司内部做了一个四十分钟的讲座!

用 iMacros 成功约到周末练车

iMacros 简单的说就是一个基于浏览器的录宏回放插件,利用它可以模拟任何人工的点击,除了手工录制,它还提供一套简单的脚本,还有 javascript,vbscript 等接口方便进行复杂的逻辑控制。听说了这个插件后我就在琢磨怎么用来自动网上约车。

我报的是东方时尚驾校预约计时班,网上约车每天从早 9 点开放到晚 9 点,只能约 7 天以内的。一般周末约的人非常多,我这次因为周末外出不能上网,错过了约车的时机,只能等人退订了我再抢,这个机会非常小,但还是有可能。

断断续续研究了几个小时,终于写出了一个 javascript 脚本调用 iMacros 的接口,并且大约半小时就成功抢到了退票,呵呵。

大概总结一下:

  • Firefox 版本的插件安装地址
  • 录制很简单,点击 record 然后鼠标键盘正常操作,结束后按 stop,然后查看脚本源码,获得第一手感性认识,然后可以对照手册自己添加一些代码
  • SET !REPLAYSPEED FAST 用来设定回放速度为最快,即执行语句中间不等待
  • SET !ERRORIGNORE YES 用来忽略错误
  • REFRESH 用来刷新页面
  • WAIT SECONDES=3 等待 3 秒
  • ONDIALOG POS=1 BUTTON=CANCEL CONTENT= 看到弹出窗口后点 Cancel

写 js 用到的接口:

  1. iimPlay("CODE:...")执行 iMacros 的脚本语句,语句可以是一段,必须以 CODE: 开始,行间要用 "\n" 分隔,返回值为负数代表执行有错
  2. iimGetLastError() 返回最近错误对应的错误信息(字符串)
  3. iimDisplay(msg) 以独立对话框形式显示一个消息
  4. SET 语句只在一个 CODE: 块中有效
  5. Tag 未找到时会默认会等待 !TIMEOUT /10 这么常时间,默认值就是 6 秒
  6. 不支持使用 document.getElementById() 来判断 tag 是否存在

有了这些就可以用 js 来处理复杂的逻辑控制,我是在先在一个循环中登录,直到登录成功,然后点击预约按钮转到约车界面,然后点击相应的表格,表格对应的 id 可以直接查看源码得到,或者用 Web DeveloperColorzilla 等插件查看,判断返回值可知是不是约成功了,成功之后再点会变成取消,所以要增加 ONDIALOG 语句来点击 Cancel 按钮。

← Previous  1 2 3 4 5 … 26 Next →