通过grub4dos引导vista和linux的双系统

机子里以前装的是Win XP和Linux双系统,出于追mm以及紧跟潮流的考虑,我重新格式化装有XP的C盘,并安装了Vista。双系统的引导成了问题,从网上搜索发现,grub4dos也在与时俱进,支持vista的引导。于是我决定通过在Vista下面安装groub4dos引导Linux。

根据grub4dos的教程,我先在命令提示符下运行
bcdedit /create /d "GRUB for DOS" /application bootsector
得到了一个类似{05d33150-3fde-11dc-a457-00021cf82fb0}的id字符串
紧接着运行如下命令,

	bcdedit /set {id} device boot
	bcdedit /set {id} path \grldr.mbr
	bcdedit /displayorder {id} /addlast

其中,{id}就是先前得到的带花括号的id字符串。

然后,将GRLDR.MBR拷贝至Vista系统盘的根目录下,如C:\。同时,也将GRLDR和menu.lst拷到系统盘的根目录下(readme文件里说的是任意FAT16/FAT32/EXT2/NTFS分区的根目录下均可,不过我没来得及尝试)。

需要注意的是,C:\GRLDR文件本来就存在,任意改个名字即可。

然后修改Grub4dos的菜单文件(C:\menu.lst)和配置Windows的系统启动(系统属性 / 高级 / 启动故障和恢复)即可。

附上我的menu.lst文件内容,均可以正常启动:

color black/cyan yellow/cyan
timeout 30
default /default

title Windows Vista
find --set-root /bootmgr
chainloader /bootmgr

title Slackware 12.0
root (hd0,6)
kernel /boot/vmlinuz root=/dev/sda7 ro vga=791

与2k/xp不同的是,先进入grub4dos的界面,然后可进入Vista的引导界面。文件名等种种迹象标明,vista的启动管理器似乎是将grub4dos写在MBR里了。

Update:
某激活软件用的也是grub4dos,进行上面某一项设置的时候可能会导致无法激活。如果是多系统,建议通过Linux将Grub重新写在MBR,再通过Grub引导windows。不推荐使用grub4dos,感觉更混乱。

btw,通过live cd或硬盘进入linux,运行grub进入grub>提示符界面后,可通过如下命令恢复mbr:

grub>root (hd0,3) #指定linux分区所在位置
grub>setup  (hd0) #将grub装到/dev/hda的MBR区。
grub>quit #大功告成,退出grub界面

Linux Shell学习笔记

年后准备的会议材料,一直没用上。本着共享的精神,拿出来晒晒吧。

Linux Shell ABC
0. 关于shell
0.1 常见的shell
    ---------------------------------------------
        shell               path            name
    ---------------------------------------------
    rc                  /usr/bin/rc         rc
    Bourne shell        /usr/bin/sh         sh
    C shell             /usr/bin/csh        csh
    Bourne Again shell  /bin/bash           bash
    Z shell             /usr/local/bin/zsh  zsh
    Korn shell          /usr/bin/ksh        ksh
    TC shell            /usr/bin/tcshell    tcsh
0.2 shell的启动、更改和退出
    更换shell:
        输入相应的命令可更改
    退出:
        - 输入exit后按
        - 在空行上键入< ^D>
0.3 shell环境变量
    可通过set命令查看,常见的有:
    HOME
    HOSTNAME
    LANG
    LC_CTYPE
    MAIL
    PS1
    PATH
    PWD
    SHELL
    TERM
    UID
    MAIL
0.4 shell元字符
    --------------------------------------------------------------
    元字符          作用                            举例
    --------------------------------------------------------------
    New Line    结束命令行
    Space       分隔命令行中的元素
    Tab         分隔命令行中的元素
    #           注释
    "           引用多字符,允许替换
    $           结束一行;间接引用shell变量         uid:"$UID"
    &           让命令到后台执行                    command &
    '           引用多字符                          '$UID'
    ( )         执行子shell中的命令列表
    *           匹配0个或多个字符                   ls /etc/p*sswd
    [ ]         插入通配符                          ls /etc/rc[0-6].d
    ^           开始一行以及否定符号
    `           命令替换                            NAME=`echo zgq`
    { }         在当前shell中执行命令列表
    |           创建命令之间的管道                  ls | wc -l
    ;           顺序执行命令                        date; sleep 1; date
    >           命令的重定向输出                    echo > /tmp/test.txt
    < 命令的重定向输入                    wc -l < /tmp/test.txt
    ?           通配符为单个字符                    ls /etc/pass??
    /           路径分隔符
    \           转义字符
    !           启动历史列表中指定的事件以及当前事件 !vi
    ~           home目录                            echo ~

0.5 Bash相关配置文件
    /etc/profile
        登录时的系统初始化文件
    ~/.bash_profile
        登录时用户专有的初始化文件
    ~/.bashrc
        登录以及每打开一个交互shell,用户专有的初始化文件
    ~/.bash_logout
        用户退出时执行的文件
    ~/.inputrc
        Individual readline initialization file

1.运行Shell脚本
    - 增加文件可执行权限
        $ chmod +x script_file
    - 直接通过shell命令执行
        $ /bin/sh script_file
        $ /bin/bash script_file
    - 脚本文件开头指定shell
        #!/bin/bash
2. Shell变量及其相关命令
    - 可写环境变量
    - 只读环境变量
        环境变量    含义
        $0          程序名
        $1 - $9     第1-9个命令行参数的值
        $*          所有命令行参数的值
        $@          所有命令行参数的值(如果它被包含在引号中,如"$@",
                    则每个参数也将各自被包含在引号中)
        $#          命令行参数的总数
        $$          当前的进程ID(PID)
        $?          上一条命令的退出状态(0 - 成功,其他输出 - 失败)
        $!          最近后台进程(在后台运行的最后一个进程)的进程ID
     - 相关命令
        - set
        - env(不如set命令完整)
    2.1 读写shell变量
        variable1=value1 [variable2=value2 ... variableN=valueN]
        注意:
            - 等号(=)前后没有空格,如果值中含有空格,须使用引号将这个值括起。
            - 多个赋值语句可写在一行,但必须用空格或分号分隔
        $ name=Guoqiang
        $ echo $name
        Guoqiang
        $ name='Zhou Guoqiang'
        $ echo $name
        Zhou Guoqiang

        $ my_uid='$UID'
        $ echo $my_uid
         $UID
        $ my_uid="$UID"
        $ echo $my_uid
        1000
    2.2 命令替换
        `command`
        $ echo now: `date`
        now: Sun Mar 23 17:44:36 CST 2008

        $ now="date: `date`"
        $ echo $now
        date: Sun Mar 23 17:45:45 CST 2008

        $ now='date: `date`'
        $ echo $now
        date: `date`
    2.3 导出环境变量
        命令export可以向后继shell进程传递变量的值
        export [name-list]
    2.4 重置变量
        unset [name-list]
    2.5 创建只读用户自定义变量
        readonly [name-list]
        类似PHP中的常量
        $ name=zgq gender=male
        $ readonly name gender
        $ echo $name $gender
        zgq male
        $ name=zhang3 gender=female
        bash: name: readonly variable
    2.6 读取标准输入
        read variable-list
3. 脚本参数传递
    - 9个参数($1 - $9)有时不够用
      可以使用shift命令将参数左移N个位置
        shift [N]
    - set [options] [argument-list]
      依次将各位置参数的值设为argument-list中指定的参数
      如果不带任何参数,set将显示所有shell变量以及他们当前的值
4. 注释与程序头
    #!/bin/bash
    #
    #
    #
5. 程序控制
    1. if-then-elif-else-fi语句
        if expiression
        then
            elif expression
            then
                ...
            else
                ...
        fi
      - expression可以使用test命令也可以使用括号
        if test $# -eq 0
        等价为:
        if [ $# -eq 0 ]
        (注意[和]前后的空格)
    2. for语句
        for variable [in argument-list]
        do
            command-list
        done

        如果没有提供argument-list,参数由命令行提供
    3. while语句
        while expression
        do
            command-list
        done

        如果死循环,就<^C>吧
    4. until语句
        until expiression
        do
            command-list
        done
    5. break和continue命令
    6. case语句
        case test-string in
            pattern1)
                command-list1
            ;;
            pattern2)
                command-list2
            ;;
            patternN)
                command-listN
            ;;
            *)
                end-command-list
            ;;
        esac

6. 常用命令集锦
    - 杀死firefox进程
      $ ps aux | grep firefox | grep -v grep |cut -c 9-15 |xargs kill -9
    - 将当前目录下php文件中的foo题换成bar
      $ sed *php -in-place -e's/foo/bar/g'
    - 根据ip查看bbs.insenz.com的访问次数
      $ cat  bbs.insenz.com-access_log  | awk '{print $1}' | sort | uniq -c | sort -nr
    - 查看远程服务器的磁盘空间状况
      $ ssh zhouguoqiang@10.0.1.33 'df -h'
    - 查看svn副本中某两个目录下的代码总行数
      $  find src/ tests/ -type f | grep -v .svn | xargs wc -l | awk '{ sum += $1; } END { print sum; }'

6. 参考资料
    - Unix教程(第二版)
        http://www.douban.com/subject/1809210/
    - man bash, man test

搭建svn://模式的svn服务器

svn可支持file:///、http://、https://、svn://、svn+ssh://等多种模式访问,其中file:///模式无须任何配置,http://和https://模式需要通过配置Subversion的Apache服务器的WebDAV协议实现。下面我们配置基于svn://模式的svn服务器。

1. 安装svn相关的软件
一般linux发行版都自带,如果没有,可去官方下载安装。

2. 创建资源库
svnadmin create /home/svnroot/repos

3. 运行svn服务
svnserve -d -r /home/svnroot/repos

4. 授权
编辑 /home/svnroot/repos/conf/svnserve.conf,去掉如下两行开头的#符号,以便禁止匿名用户的读写
anon-access = none
auth-access = write
password-db = passwd

5. 添加svn用户
编辑conf/passwd文件,可以明文形式添加密码:
yourName = yourPasswd

6. 导入仓库
为了便于以后维护,建议每个项目使用三个顶级目录(branches、tags和trunk),首先需要创建一临时目录存放该目录结构:
mkdir /tmp/myproject/{branches,tags,trunk} -p

可以在本地通过file:///方式导入至仓库里:
svn import /tmp/myproject file:///home/svnroot/repos/myproject -m “initial import”

其中,file:///home/svnroot/repos/myproject即是新项目的svn路径,而/tmp/myproject名字可以随意定义,不一定和svn里的项目名称一致。

7. 检出项目
svn checkout svn://192.168.1.118/myproject/trunk myproject
需要输入用户名密码

至此,完成了svn服务的基本配置。

参考资料:
1. svn服务端搭建
2. svn手册

vim远程修改文件产生的安全隐患

刚才无意中通过浏览器看到了wordpress配置文件里的信息了,现在想想仍心有余悸。

如果你像我一样,将vim作为首选编辑器;如果你也像我一样,有时候需要远程修改文件。那么,请注意了,通过vim远程修改文件,可能会产生~结尾的备份文件,由于服务器一般都无法解释~后缀文件,这将把代码泄露给客户端。如果巧好是某个配置文件,后果更是不堪设想。

解决方法:
1. 通过设置nobackup和nowritebackup参数,取消vim的自动保存功能
2. 让web服务器解释~后缀文件

禁用Vim中鼠标点击时的虚拟选中模式(visual mode)

自从升级操作系统后,Vim相应也升级到了当时的最新版7.1。可是这个Vim7.1使用鼠标时会默认进入虚拟选中模式(visual mode),就好像通过v选中的一样。搜索一下,有人碰到过这个问题,原来可以通过下面的方式禁用:
1.命令行
:set mouse-=a
2.添加:set mouse-=a至配置文件~/.vimrc

都是\n惹的祸

昨天郁闷了半天。自从发现echo和wc命令的组合可以省去我数某个字符串的长度时,我就一直使用这个超级无敌的命令组合。但是echo 之后默认带换行(\n)有时也会带来意想不到的麻烦。

比如
echo 123456789 | wc --chars
10

去掉echo后面默认带的换行符,就对了:
echo -n 123456789 | wc --chars
9

gmail也有打盹的时候?

Google的服务一向以稳定而著称,但我却看到了gmail在打盹。

刚才打开浏览器,通过Gmail Notifier 插件登录gmail。其实我以前保存了密码,但它却提示我验证失败,于是我输入密码重新登录。一串提示性的文字一闪而过,大意是说我的网速慢之类的。此后本来应该显示熟悉的gmail首页,但是紧接着却出现了白底黑字的javascript代码,还以为是我搞错了,重新打开一个标签登录,依然如此。

gmail source
具体代码如下(为了便于阅读,我删除了其中的空行):

var BrowserSupport_ = {
IsBrowserSupported : function() {
var agt = navigator.userAgent.toLowerCase();
var is_op = (agt.indexOf("opera") != -1);
var is_ie = (agt.indexOf("msie") != -1) && document.all && !is_op;
var is_ie5 = (agt.indexOf("msie 5") != -1) && document.all && !is_op;
var is_mac = (agt.indexOf("mac") != -1);
var is_gk = (agt.indexOf("gecko") != -1);
var is_sf = (agt.indexOf("safari") != -1);
if (is_ie && !is_op && !is_mac) {
if (agt.indexOf("palmsource") != -1 ||
agt.indexOf("regking") != -1 ||
agt.indexOf("windows ce") != -1 ||
agt.indexOf("j2me") != -1 ||
agt.indexOf("avantgo") != -1 ||
agt.indexOf(" stb") != -1)  {
return false;
}
var v = BrowserSupport_.GetFollowingFloat(agt, "msie ");
if (v != null) {
return (v >= 5.5);
}
}
if (is_gk && !is_sf) {
var v = BrowserSupport_.GetFollowingFloat(agt, "rv:");
if (v != null) {
return (v >= 1.4);
} else {
v = BrowserSupport_.GetFollowingFloat(agt, "galeon/");
if (v != null) {
return (v >= 1.3);
}
}
}
if (is_sf) {
if (agt.indexOf("rv:3.14.15.92.65") != -1) {
return false;
}
var v = BrowserSupport_.GetFollowingFloat(agt, "applewebkit/");
if (v != null) {
return (v >= 312);
}
}
if (is_op) {
if (agt.indexOf("sony/com1") != -1) {
return false;
}
var v = BrowserSupport_.GetFollowingFloat(agt, "opera ");
if (v == null) {
v = BrowserSupport_.GetFollowingFloat(agt, "opera/");
}
if (v != null) {
return (v >= 8.0);
}
}
if (agt.indexOf("pda; sony/com2") != -1) {
return true;
}
return false;
},
GetFollowingFloat : function(str, pfx) {
var i = str.indexOf(pfx);
if (i != -1) {
var v = parseFloat(str.substring(i + pfx.length));
if (!isNaN(v)) {
return v;
}
}
return null;
},
tz_path : ';path=/'
};
if (window.location.href.toLowerCase().indexOf('google.com') > 0) {
BrowserSupport_.tz_path += ';domain=.google.com';
}
document.cookie = "TZ=" + (new Date()).getTimezoneOffset() +
BrowserSupport_.tz_path;
var is_browser_supported = BrowserSupport_.IsBrowserSupported();

仔细看了一下页面上的代码,主要是对域名、时区以及浏览器的兼容性做判断的。值得一提的是它还对pda、sony/com2、safari以及opera等客户端作了专门的判断。

用工具查看页面的http信息,如下:

Etag: "hyuaanj8ksp6"
Last-Modified: Fri, 05 Sep 2003 02:11:15 GMT
Content-Type: text/javascript; charset=UTF-8
Cache-Control: private
Expires: Fri, 21 Dec 2007 15:12:16 GMT
Content-Encoding: gzip
Content-Length: 684
Server: GFE/1.3
Date: Sat, 01 Dec 2007 15:12:16 GMT

200 OK

与此同时,我访问了google提供的企业邮局,则显示正常。

当雅虎邮箱再次遇上乱码

最近碰到一件奇怪的事情,使用gmail收到来自雅虎信箱(yahoo.com.cn)回复的邮件时,标题总是或多或少出现乱码。

于是我注册一个雅虎信箱,分别给gmail和公司邮箱(使用客户端sylpheed收信)发送邮件。如果标题超过20个中文,收到的邮件标题确实会显示部分乱码。有意思的是两者显示乱码的方式还不一样:gmail将第20个中文后的字符显示为乱码;sylpheed则将第21、22个中文显示为乱码。

smtp协议似乎并没有对邮件标题长度做限制,不知雅虎信箱为何对标题的第40个字符这么敏感。

btw,在网上搜了一下,发现雅虎邮箱在年初也曾出现过乱码

读取mplayer/ffmpeg运行时的输出信息

由于使用了退格(backspace)、覆盖(substitute)、垂直方向(vertical tab)的tab等控制字符,很难直接读到mplayer/ffmpeg运行时的信息。其实按字符读取并过滤其中的控制字符,便可以还原其输出信息的“真面目“了。以下是在php中的实现:

< ?php

$src = '/path/to/input.mp3';
$dst = '/path/to/output.flv';

$cmd = '/usr/local/bin/ffmpeg -i "%s" -acodec libmp3lame  -f flv   -y "%s" 2>&1 ';
$cmd = sprintf($cmd, $src, $dst);
$handle = popen($cmd, 'r');
while(!feof($handle)) {
    // 按字符读取
    $charset = fgetc($fd);

    // 如果是垂直tab符号
    if ($ord($charset) == 13) {
        printf("%s\n", $line);
        $line = '';
        continue;
    }

    // 如果是退格或覆盖符号
    if (ord($charset) == 10 || ord($charset) == 32) {
        continue;
    }
    $line .= $charset;
}
pclose($handle);

?>

ps: 看不出wordpress有时也很bt, 昨天这篇文章发了半天都返回503错误,后来发现是文章里&#112open一词导致的,我只好用字符p的html实体&#112;来代替了

mysql数据库迁移备忘(4.0.22 -> 5.0.37)

旧mysql版本为4.0.22,新数据库版本为5.0.37,旧库中使用的字符集为utf8,phpmyadmin版本均为2.9.11,具体过程如下:
先在使用phpmyadmin从虚拟主机mysql4.0.22的数据以sql语句方式导出,然后在本地mysql5.0.37上同样使用phpmyadmin导入,发现有如下地方需要修改

old new 备注
`type` enum(‘原创’,’转载’) NOT NULL default ‘转载’, `type` enum(‘原创’,’转载’) NOT NULL, 如果enum的值为英文,则无需修改
) TYPE=MyISAM AUTO_INCREMENT=185 ; ) ENGINE=MyISAM DEFAULT CHARSET=utf8 AUTO_INCREMENT=185 ;
) TYPE=HEAP MAX_ROWS=500; ) TYPE=HEAP MAX_ROWS=500;