Total Pageviews

Saturday 27 October 2012

bash 4

1. 从 command_not_found_handle 说起
发现Ubuntu(以及openSUSE)都提供了一个非常友好的功能:当你输入错误的、不存在的命令的时候,系统(实际上是bash调用应用程序)会给出相当有建设性的建议:
hongchuan@ubuntu:~$ gvim
程序“gvim”已包含在下列软件包中:
* vim
* vim-gnome
* vim-tiny
* vim-gtk
* vim-nox
请尝试:sudo apt-get install <选定的软件包>
hongchuan@ubuntu:~$ mc
程序“mc”尚未安装。  您可以使用以下命令安装:
sudo apt-get install mc
不访先思考一下Ubuntu是如何实现这个功能的。
………………………………
是的,要“捕获”这个“错误”,通过bash无疑是最直接和高效的。
……………………
bash 4提供了一个command_not_found_handle“钩子”,当bash遇到“命令找不到”时,假如这个函数被“定义”,则command_not_found_handle $1 被执行。
Ubuntu的command_not_found_handle是这样定义的:
command_not_found_handle () {
if [ -x /usr/lib/command-not-found ]; then
/usr/bin/python /usr/lib/command-not-found — $1;
return $?;
else
if [ -x /usr/share/command-not-found ]; then
/usr/bin/python /usr/share/command-not-found — $1;
return $?;
else
return 127;
fi;
fi
}
/usr/lib/command_not_found是一个用Pythonp写的处理“错误”、并提供“建议”的程序。
随便提一下,我当前的Ubuntu版本是10.10(lsb_release -r ),bash是4.1.5(1)-release(echo $BASH_VERSION),当前系统提供的bash手册中,完全没有提到command_not_found_handle,而GNU网站上的bash手册中则有详细说明:Command-Search-and-Execution
2. Coprocesses (协进程/异步支持)
bash 4新增的内置命令coproc,用于在后台启动一个子shell,并将command放在子shell中执行,在后台执行的进程称作 coprocess(协进程)。当前shell不需要等待command执行完成,于是有“异步”之功效。coproc command与command &某种程度上效果相同。
如何使用 coproc :
举个例子,执行  coproc  COMMAND,那么 coproc 会做几件事情:
1.在后台启动子shell,PID值放在变量 COPROC_PID中。
2.在子shell中执行COMMAND。
3.建立两个“双向管通”,管道的文件描述符为${COPROC[0]}和${COPROC[1]}。
这样,就建立了一个“父进程”与“子进程”之间进行通信的方式(管道)。其中 ${COPROC[0]} 连接着“协进程”的“标准输出”,${COPROC[1]}连接着 “协进程”的“标准输入”。父进程通过${COPROC[0]}读取“协进程”的输出,通过${COPROC[1]}向子进程发送数据。
应用举例:
#!/bin/bash
rw() {
while read line ; do
echo $line >> log.txt
done
}
coproc  rw
cat >&${COPROC[1]}
这个程序在前台启动一个cat,后台启动一个read的循环,读取前台的输入并将输入写入log.txt文件。
另一个:
#!/bin/bash
process_line() {
local line=$@
echo “$line”
}
coproc tail -f /var/log/messages
while read line ; do
process_line “$line”
done <&${COPROC[0]}
“协进程”逐行输出/var/log/messages新增的行,前台程序逐行处理。
实际上,在bash 3中,在没有提供coproc的环境里,也可以使用这样的“思想”,实现“shell的多进程编程”。
3. 关联数组
bash支持的新“数据结构”,类似于Python的字典,PHP的关联数组。就是
p[name]=’hongchuan’
p[age]=28
p[site]=’http://www.urdomain.com’
可以使用字符串作为数组的下标,引用值时${p[name]},${p[site]},${p[age]}。
使用“关链数组”需要事先声明:
declare -A p
4. 大小写转换
declare -l hostname
declare -u  MAC
声明变量hostname为小写,当执行hostname=”WWW.urdomain.COM”时,hostname的值为www.urdomain.com。
声明变量MAC为大写,当MAC=”00:1b:2f:4c:19:7e”,MAC的值为 00:1B:2F:4C:19:7E。
5.  前置0
bash3中,为了产生0021这样的数,我是这么做的
for vlan in {1..10}; do
vlan_id=`printf %4d vlan|sed ‘s/ /0/g’`
……
done
bash4中,可以这样:
for vlan_id in {0001..10}; do
……
done
6. mapfile (readarray)
将文件装入数组
mapfile aa < log.txt
将文件log.txt以行为单位赋值给数组aa
callback() {
echo ${aa[@]}
}
mapfile -C callback -c1 aa < log.txt
help mapfile 更多详情。这个mapfile功能相当适用。
7. 新增两个重定向简写符
&>> 和 |&
&>> 等价于 >> file 2>&1
|&     等价于 2>&1 |
更多新特性,见官方手册。


有用的链接:
http://www.gnu.org/software/bash/
http://wiki.bash-hackers.org/bash4
http://www.gnu.org/software/bash/manual/bashref.html