用 mkdir 確保 shell script 執行的互斥性

有些時候,你不希望一個 script 同時有兩個以上的 instance,這個時候你可能有很多想法,例如利用檢查 pid file 的方法,或者是找一個 lockf(1) 之類的程式幫你處理這些事情。(老實說 FreeBSD 的 lockf(1) 的確蠻方便的,尤其是對於懶惰寫 code 的我來說。)

但是這會有另外一個問題,不是每個 OS 都有提供 lockf(1),有些就只給你 lockf(2)。所以我就得換個方法作,首先,我想到這樣的寫法

if [ -f $lockfile] ; then
    touch $lockfile

利用一個 lockfile 來確保互斥性,只不過 -f 與 touch 之間還是有機會產生 race condition。結果在讀了一些文章之後,我發現有人說 mkdir(2) 是 atomic 的(我目前還沒有找到什麼佐證的資料,NFS 就先放一旁吧……),也有人就用 mkdir(1) 來確保同時只會有一個 shell script 的 instance,再搭配 trap 來處理一些 signal,這樣似乎就可以暫時取代 lockf 了……。

最後的版本就像這樣,應該還有很多問題,但先這樣吧。

ToLock()
{
        progName=`/bin/basename $0`
        lockname="/tmp/$progName.lock"

        if /bin/mkdir "$lockname"
        then
                # Remove lock directory when script terminates
                trap '/bin/rmdir "$lockname"' 0 1 2 3 15
                trap "exit 2" 1 2 3 15
        else
                echo >&2 "another $progName is running?"
                exit 1
        fi
}

最後附上幾篇參考資料

你今天 static code analysis 了嗎?

最近才稍微看了一下手邊專案的程式碼,不能說有什麼太多的問題,只是就制度面而言,其實還有更多可以改善的地方。

公司以往的作法是這樣,你先 check-in code,然後等到一個禮拜的 static code analysis 再進行全面性的更正。但我想 check-in 之後的 static code analysis 只能說是最後一道防線,在這之前,就只能端看開發者的自由心證。

所以,如果要等公司的工具告訴你問題之前,為什麼不先想辦法先作一次呢?自己先作一次有幾點好處。

  • 確保 check-in 的 code 跑出來的 unit test 結果正確,降低事後修正造成的副作用
  • 減少 submit log 上太多與 feature 無關的 log(例如 strcpy fixing)

而現有的 static code analysis 的工具你可以參考 List of tools for static code analysis 然後選擇用的順手的一個,以 C/C++ 而言,我剛剛稍微玩了一下 RATSflawfinder,他們的確能夠提供一些有用的資訊,像是不該使用 gets,或是使用 strcpy 會造成的危險他都能一一列出。

然而 static code analysis 就真的足夠了嗎?我想答案勢必是否定的。

HTML Form 中 disabled 的元件

HTML Form 中 disabled 的元件的值不會被送出去阿 XDDDDD

http://www.w3.org/TR/html401/interact/forms.html#h-17.12.1是這樣說的:

In this example, the INPUT element is disabled. Therefore, it cannot receive user input nor will its value be submitted with the form.

然後抱怨一下,不是這樣無聲無息地把 exception 吃掉吧,這樣 debug 很困難的……。

EQATEC Profiler – Compact Framework Code Profiler

雖然大概三年左右沒寫 .NET Compact Framework 的東西,不過偶爾會看一下那方面的消息。

之前有大概搜尋一下 Windows Mobile 上的 native code profiler,那些 profiler 通常不是要錢,要不然就是很難用。不過剛剛看到這篇 Compact Framework Code Profiler,對於用 .NET Compact Framework 開發程式的人而言,好的 profile 往往是找出效能瓶頸的救星,而且他居然不用錢,這還能要求什麼呢?

EQATEC Profiler

The global statement in python

寫 code 時候踩到地雷,果然沒唸好 scope 果然是不行的

#!/usr/bin/env python

flag = True

def test():
    flag = False

print flag
test()
print flag

結果似乎和想的不太一樣。


# python 2.py
True
True

結果翻了一下 The global statement 才知道

It would be impossible to assign to a global variable without global, although free variables may refer to globals without being declared global.

工作之外更需要學習

星富哥說工作的本身會榨乾一個人的活力,但我覺得工作之於我,工作並不是榨乾我的能力,而是太多瑣碎的事物使我無法更專注地學習。我好像能夠看見幾年後的自己,若是繼續維持這樣的生活下去,我就只是這樣而已,沒有進步,雖然經歷過幾個專案,或是幾個產品,我技術上是沒有進步的。

不過也因為現在的工作必須廣泛閱讀一些東西,像是我選修的一門課在探討跨平台的程式開發,讓與會的每個人分享閱讀 Cross-Platform Development in C++: Building Mac OS X, Linux, and Windows Applications 這本書,原本我想選關於 XUL 還有 XPCOM 的主題,結果這兩個主題很快就被我同事選走了。我最後因緣際會選了 Install 的章節,昨天在捷運上翻了一下,也包含許許多多有趣的主題,像是 XPInstallNSIS

結果這本書講了很多,Tinderbox、Autotools、wxWidgets 也許還有 CMake、GNUstep 等等的東西,但是這些東西在工作上都不見得會出現,工作常常是需要解決舊有產品的問題,這些有趣的東西就只能留待下班之後,或是假日時間。我會希望自己能好好的學習,像是工作需要學習的 python,我也能必須更廣泛的閱讀,思考是不是有更好的解決方案。否則我只是快速的解決一個問題,而並非創造。

我想這是我所需要的,所以我選擇在工作之餘再進行學習,一方面是興趣,一方面也是想不要太快被取代吧。

p.s.
Learning Python Design Patterns Through Video Lectures

vim 裡的 python autocomplete

pydiction

http://www.vim.org/scripts/script.php?script_id=850 的東西抓回來丟到 .vim 下面,然後按照 readme 的作,之後按 ctrl+n 或者 ctrl+p 就可以看到漂亮的下拉選單了。

強者我同學 Pky 應該會叫我去 http://wiki.python.org/moin/IntegratedDevelopmentEnvironments 找個好用的吧,不過我就是喜歡用 vim 啦~~

聽 128kbps 的台北愛樂

#!/bin/sh

url=`/usr/local/bin/wget -q -O - \
'http://hichannel.hinet.net/player/radio/index.jsp?radio_id=228' \
 | grep setMovieFile | awk 'BEGIN {FS = "\""} \
 {print "http://hichannel.hinet.net/player/radio/"$2}'`

mmsurl=`/usr/local/bin/wget -q -O - "$url" | grep Radio_ | \
head -1 | awk 'BEGIN {FS = "\""} {print $2}'`

echo ${mmsurl}

jnlin 以前寫的改,如果你用 foobar2000 的話也可以搭配 Acropolis 寫的 foo_input_mslive 這個 plug-in 來聆聽。

Python: range() 與 xrange()

http://docs.python.org/lib/built-in-funcs.html

This function is very similar to range(), but returns an “xrange object” instead of a list. This is an opaque sequence type which yields the same values as the corresponding list, without actually storing them all simultaneously. The advantage of xrange() over range() is minimal (since xrange() still has to create the values when asked for them) except when a very large range is used on a memory-starved machine or when all of the range’s elements are never used (such as when the loop is usually terminated with break).