May 23, 2010

terminal, bash和screen的配合

首先, 术业有专攻, 命令行和图形界面不是水火不容, 我都用的很多, 少了哪个也不行.

其中关于命令行, 我基本上不进console, 毕竟分辨率, 字体, 中文什么的都比较恼火. 自己电脑就是xterm+screen+bash, 办公室就是用putty+ssh+screen+bash. 想要有一个舒服的使用环境, 就得把这几个家伙配合好.

想要实现一个什么效果呢? 最好运行screen的时候, 每个window的title为路径或者当前运行的程序, xterm的title为screen: 加上当前window的title; 而单独运行xterm的时候, xterm的title为user@host: path. 比较晕是吧? 看我的效果图:

下面是一些关键的配置, 其它部分在此: https://github.com/adam8157/dotfiles

bash的.bashrc:

#screen and xterm's dynamic title
case $TERM in
	xterm*)
		# Set xterm's title
		TITLEBAR='\[\e]0;\u@\h:\w\a\]'
		PS1="${TITLEBAR}${PS1}"
		;;
	screen*)
		# Use path as title
		PATHTITLE='\[\ek\W\e\\\]'
		# Use program name as title
		PROGRAMTITLE='\[\ek\e\\\]'
		PS1="${PROGRAMTITLE}${PATHTITLE}${PS1}"
		;;
	*)
		;;
esac

screen的.screenrc:

# Caption line
caption always "%{= R}[ %{=b b}%-w%{=rb db}%>%n %t%{-}%+w%{-b}%< %=%{R}][%{M}%D %M %d %{G}%c%{R}]"

# Dynamic title
shelltitle '$ |bash'

# Set xterm's title
hardstatus string "screen: %t"

bash中主要是设置了几个escape sequences, 具体都是screen和xterm自己定义的, 把它们塞到PS1中, 看不到的同时还能给screen和xterm发信号, 让它们改对应的title.

screen中状态栏选用Caption而不用Hardstatus实现, 是因为要把xterm的title伪装成Hardstatus, 这个可能算个历史遗留问题, putty也是这么处理的. shelltitle就是实现将所运行程序的名称作为screen的title的功能, 默认bash,, 有命令的话就是”$ “后面的第一个字符段.


May 23, 2010

Bash下实现alias补全

我是个懒人. 很多较长的命令, 比如apt的搜索, 安装, 卸载和清理都让我搞成了alias. 但简化输入的同时也带来个问题: 完整的命令配合bash_completion可以实现自动补全包名称, 现在用alias却得小心翼翼地输入. 这怎么行? 必须解决掉.

之前的补全是配合bash_completion实现的, 所以很明显, alias补全也要从研究bash_completion入手. 分析/etc/bash_completion可以看出, bash_completion实现了很多用来获得补全项的函数, 然后用bash的内置命令complete将命令和函数对应起来以实现补全. 所以, 解决方案一目了然, 将函数提取出来和我自己定义的alias对应起来就好.

以下是.bashrc中的配置

#completion
if [ -f /etc/bash]_completion ]; then
	. /etc/bash_completion
fi

_show_installed()
{
	local cur
	COMPREPLY=()
	cur=`_get_cword`
	COMPREPLY=( $( _comp_dpkg_installed_packages $cur ) )
	return 0
}

_show_all()
{
	local cur
	COMPREPLY=()
	cur=`_get_cword`
	COMPREPLY=( $( apt-cache pkgnames $cur 2> /dev/null ) )
	return 0
}

complete -F _show_all $default ai aw
complete -F _show_installed $default ap

#alias
alias ai='sudo apt-get install'
alias ap='sudo apt-get purge'
alias aw='apt-cache show'

解释一下: _show_installed()用来获得已经安装的包名称, _show_all()用来获得源里所有的包名称. complete命令用以建立对应关系. 最后是我需要补全的alias. 很简单吧, 如果你有其它需要补全的alias, 函数都在/etc/bash_completion中, 提出来照着改就是了.

PS: zsh的补全功能很强, 不用这么折腾, 有兴趣的朋友也可以试一下.


May 21, 2010

mutt强大的hook规则

以前也知道mutt可以利用hook对特定情况特殊处理, 但是一直没需求, 直到上个月订阅了中文内核邮件列表.

这个列表会在邮件最后放一段文字, 所以发PGP签名的邮件就会失败. 很明显, 签名就是保护邮件正文不被修改的, 但这个邮件列表就是要改你的邮件正文, 自然不行. 问题在于我喜欢设置为默认自动签名, 所以每次给这个邮件列表发信就得手动改PGP为Clear, 哪次忘了改? 好吧, 你的回复就消失无踪了.

好在强大的mutt总是能满足我的各种需求, 想要默认签名, 但是发给中文内核列表的不签? 没问题.

下面是配置:

send-hook ~A "set pgp_autosign"
send-hook "~C linux-kernel@zh-kernel.org" "set nopgp_autosign"

解释一下, 第一句设置默认情况为自动签名, 第二句匹配所有在To:或者Cc:中包含linux-kernel@zh-kernel.org的发送或者回复邮件, 此时取消自动签名.

===============无聊的分割线===============

刚写到这里, 又想到了hook的另一个应用: 我的mutt是配合内置imap的, 绑定了d为移动到Gmail的Trash, 但是如果你要删除Trash中的邮件, 就得再绑定一个键(例如D)为删除, 很麻烦. 理想情况是在别的文件夹中绑定d为移动到Trash, Trash中绑定d为删除. 这个实现起来依然轻松, 可以利用folder-hook.

直接上配置:

folder-hook . 'macro index,pager d "=[Gmail]/Trash" "Mark message as trash"'
folder-hook 'Trash' 'bind index,pager d delete-message'

mutt实在是强大的过份, 想怎么玩怎么玩, 向mutt致敬!


May 18, 2010

赛季结束--冠军!

Yeah, 99分创历史记录夺冠, 巴萨是最棒的!

祝愿巴萨下赛季多线开花, 也祝大家身体健健康康.

…不多说了, 贴张图, 补觉去…


May 15, 2010

vim中单个文件多个备份的实现

经常备份绝对是个好习惯, 一个救过我很多次的好习惯.

编辑器我只用vim, vim也有自动备份的功能, 但是存在一个问题: vim默认一个文件只对应一个备份, 所以你只能回退一次, 再之前的版本就看不到了. 这是不够用的, 也是不可容忍的, 状况随时会发生, 我们需要对一个文件保存多个备份, 最好每次修改就备份一次, 而且都保存下来.

当然, vim有基于git等版本控制系统的备份插件, 个人觉得有点小题大做了, 有点麻烦, 而且使得vim的配置和插件目录显得臃肿, 跨平台能力也不强.

我的方案是靠vim自己来实现, 每次修改就保存一个备份, 备份的文件名中包含修改的时间以方便识别. 下面是我的配置: 1, 打开备份功能; 2, 设置备份目录; 3, 每次写缓冲之前设置备份文件的后缀格式为当前的”.月-日-时-分”. 默认后缀是”~”, 不存在变化, 所以只对应一个备份. 像我这样配置后, 最后的效果会类似这样: foo.c.5-15-17-30, foo.c.5-16-01-25.

" Turn backup on
set backup

" Set backup directory
set backupdir=$HOME/.vim/backup

" Keep more backups for one file
autocmd BufWritePre * let &backupext = strftime(".%m-%d-%H-%M")

May 12, 2010

shell脚本中的空格

一直不太理解shell脚本中为什么那么多空格不可省略(比如[和]), 又有那么多空格不可以有(比如=), shell脚本为什么对格式要求这么高?

查了好多, 基本上都在总结哪里必须空格, 哪里必须不带空格. 明显, 这不是问题的本质所在. 虽然我脚本写的不多, 但是我总感觉shell脚本很优雅. 一门优雅的语言, 如shell和c, 应该是原理决定规则, 而不是像C++一样, 规则去决定实现. 不要激动, C++之父Bjarne Stroustrup就说过, 他实际上是创造了一堆他心目中的强大的面向对象语言的理论规则, 并且他不认为有人能够完全的理解C++.

扯远了, 那么关于shell的空格要求是个什么原理呢? 其实, 和你表观看到的不一样, 有些shell表达式其实是命令风格的函数, 例如”[”, 实际上, 它是个和test差不多的函数, 它后面跟的, 包括”]”, 都只是它的参数, shell中输入命令的时候要靠空格来区分各个参数, 这里也是一样. “=”两边不能有空格同样也是因为它的命令风格要对这些进行区分的要求. 虽然很诡异, 但是也可以理解, 毕竟shell脚本就是逐行运行的命令.

有些知识的积累就该是这样, 去理解而不是去总结. 就像c的数组下标为什么从0开始, 只要明白了a[i]同等于*(a+i), 一切都是那么自然.


May 10, 2010

可怜的鸭子妈妈

贴个图, 调剂下. 全技术文章显得博客太单调了.

ggarlic同学的Google Reader分享看到的. 好可怜, 但是也挺可爱的, 相信拍照的人已经出手相救了…


May 10, 2010

清理Debian内核和头文件的脚本

改自bones7456清理ubuntu内核的脚本, 原文地址在此: http://li2z.cn/2010/02/28/clean_ubuntu_kernel/.

Debian和Ubuntu的包命名方式稍有不同, 不能直接用, 改了下, 再就是避免删除元包, 增加了响应输入的功能.

#!/bin/sh

CURRENT="`uname -r | awk -F"-" '{print $1"-"$2}'`"
HEADERS=""
IMAGES=""
ARCH="amd64"

for HEADER in `dpkg --get-selections | grep ^linux-headers | grep -v "${ARCH}" | awk -F"-" '{print $3"-"$4}'`
do
	if [[ "$CURRENT" < "$HEADER" ]]
	then
		echo "The running kernel is not the newest. $CURRENT < $HEADER"
		exit 1
	else
		[[ "$CURRENT" != "$HEADER" ]] && {
			HEADERS="${HEADERS} linux-headers-${HEADER}-${ARCH} linux-headers-${HEADER}-${ARCH}-common"
			IMAGE="`dpkg --get-selections | grep ^linux-image | grep "${HEADER}" | awk '{print $1}'`"
			IMAGES="${IMAGES} $IMAGE"
		}
	fi
done

if [[ -z "$HEADERS" ]]
then
	echo "There is no old kernel or headers need to be cleaned."
	exit 0
fi

echo
echo ------------------------------------
echo "$IMAGES $HEADERS"
echo ------------------------------------
echo

read -p "Really wanna remove these packages? [y/N] " REPLY

case $REPLY in
	y | Y )
		sh -c "sudo apt-get purge $IMAGES $HEADERS" ;;
	* )
		echo "The operation is cancelled." ;;
esac

May 9, 2010

给优盘添加FreeDOS启动项

虽然我不用Win, 但是给优盘添加个FreeDOS启动项还是会方便很多的, 帮别人重装Win, 自己刷BIOS什么的都得用到.

之前优盘上就装的Grub2, 有Puppy和Debian的启动项, 所以仍然选这个方案.

需要用到的东西: balder10.img(就是freedos的镜像, 官方有下载地址), syslinux(只用到里面的memdisk).

我这优盘已经装上Grub2了, 没装的同学按自己的路径执行:

# grub-install --root-directory=/media/sdb1 /dev/sdb

然后就只剩下写grub.cfg了, 注意你的路径:

set root=(hd0,1)
menuentry "FreeDOS" {
	linux16  /boot/freedos/memdisk
	initrd16 /boot/freedos/balder10.img
}

FAQ:

1, 为什么不选freedos的livecd而选了非官方的镜像? 因为livecd是用来安装的, 直接能用的命令很少.
2, memdisk是用来干什么的? 用来装载镜像模拟软盘, 磁盘, CD.
3, 为什么不用WinPE, 一没那么大空间用来浪费, 二goto Warning

Warning:

有的同学一看到memdisk的功能又要开始激动了, 这不就能启动所有的ISO了么? 在下不才, 研究过. 答案是, 不能, 目前的硬件体系永远也不能启动所有的ISO镜像!
实模式的系统和用INT 13中断启动的可以, 因为内存映射没变. 而其它的大多都不可以, 可以的要么是引导起来的内核自己可以用ISO(很多linux发行版都支持), 要么是用INT 13启动某种镜像(如WIM).
当然有很多解决方案, WinVBlock什么的, 说到底都是又生成了一种RAM disk.
总而言之, 想要让启动后进入保护模式的系统ISO直接被引导起来, 目前的硬件体系不允许.


May 9, 2010

倒数第二轮

昨晚的比赛看得我很紧张.

虽然占着榜首并领先一分, 但是总感觉最后几轮有点被动. 还好, 虽然被追了俩, 但还是守住了三分.

关于瓜迪奥拉, 虽然是少帅, 但是实力远比年龄成熟, 丢第一个球的时候只有他意识到了危险.

关于博杨和佩德罗, 表现越来越好, 而且风格很适合巴萨.

关于阿尔维斯, 之前一直不太喜欢, 但是我, 错了.

关于梅西, 希望世界杯时状态依然完美.

关于伊布, 人很好, 只是不太适合巴萨.

关于拉波尔塔, 别听那俩主持人的, 什么成熟不成熟的, 你也是球迷, 你不只是在管理一个俱乐部, 想激动就激动.

关于巴塞罗那, 不着急高兴, 下一场依旧漂亮得拿下再说.

关于赛维利亚, 果然是个很神经质的球队, 不过我喜欢, 因为我也神经质.

关于我, 起早了, 觉没补够.