Bash 4.0 新功能概览
Bash 是 Linux 平台下使用最多的 Shell,虽然 Bash 4.0 早已经发布了,然而毕竟是主要版本,各大发行版都对其采用了谨慎的态度。就在昨天(2009.7.1),Arch 将 Bash 加入了 Core 仓库,这意味着 Bash 4 已经被 Arch 认可为稳定版本了。
那么,Bash 4 为我们带来了那些改进呢?我们来看一下。
新的或者改进的命令或关键字
- 新的"coproc"关键字:Bash 4 引入了“协同进程”(coprocesses)的概念,这允许你在后台打开程序,并与它的输入输出数据流进行交流。
- 新的"mapfile"内置命令:直接将文本文件读入到数组里面,它允许你设置读入的行数,还允许指定回调函数,这在显示进度条的时候很有用。
- 对"case"关键字的修改:新增
;& 终止符,用于执行下一个动作列表而不是终止 case 结构;新增 ;;& 终止符,用于继续检测下一个表达式(pattern)。 - 对"declare"内置命令的修改:-p 现在显示所有已声明的属性和值。-l、-u 分别用来声明内容为小写、大写的变量。-c 用于声明标题化的变量。-A 用于声明联合数组。
- 对"read"内置命令的修改:-t 指明超时时间,可以是分数。-i 可以用一些文本来预加载输入缓冲区(当启用 Readline 时,使用 -e)。
- 对"help"内置命令的修改:帮助文本的格式更好,更加易读。-d 显示帮助摘要,-m 显示 manpage 风格帮助。
- 对"unlimit"内置命令的修改:除了 POSIX 模式下的 512 字节块大小限制之外,新增两种:-b 为最大 Socket 缓冲区大小,-T 为最大线程数。
扩展(Expansions)
- 大括号扩展:产生一行数字的时候允许前置 0。
- 参数扩展:通过添加操作符,使参数在扩展时改变大小写。
- 子字符串扩展:当在位置参数中使用子字符串扩展时,以 0 开始的索引将使 $0 前缀在列表中,而不是以前的 $1。
- 文件名替换:新的 Shell 选项 globstar,将对 ** 进行递归的文件名替换;新选项 dirspell 将启用文件夹名拼写修正。
联合数组(Associative Arrays)
联合数组是一个以任意字符串索引的数组,例如:
declare -A ASSOC ASSOC[First]="first element" ASSOC[Hello]="second element" ASSOC[Peter Pan]="A weird guy"
重定向(Redirection)
新的 &>> 符号将标准输出和标准错误输出追加到指定文件,与 >>FILE 2>&1 相同作用。而 |& 与 2>&1 | 相同作用。
新的 Shell 变量
- BASHPID:包含当前 Shell 的 PID。
PROMPT_DIRTRIM:指明提示符下未缩短的路径的最高极。
新的 Shell 选项(默认关闭)
杂项
在没有找到命令时,Shell 会试图调用 command_not_found_handle 这个函数,可以用这个功能显示更友好的出错信息。
set -e (errexit) 模式的行为已经发生变化,变得更加直觉化。
轻松建立 Ubuntu/Debian 源镜像
服务器上的源是 Debian 的,考虑到学校里面已经没有多少人使用 Debian,而使用 Ubuntu 来做推广显然更加合适,同学们遇到什么问题,也可以得到更好的支持,于是决定把 Debian 源换成 Ubuntu 的。 由于脚本的需要,最好建立一个文件夹来记录最后同步的时间:
然后建立脚本 anonftpsync。拷贝下面的脚本存放在稳妥位置。
设置权限。确定脚本可以被执行,目标目录有写权限。
添加计划任务。这里使用 crontab 设置,-e 选项表示编辑设置:
输入下面的一行,表示每天凌晨 2:00 运行 /usr/local/bin/anonftpsync,添加完毕保存:
使用下面的命令查看是否添加成功:
Arch Linux 下是:
接下来就是等待咯,如果你迫不及待,可以直接运行脚本同步。 如果对 cron 不够明白,可以参考:计划任务工具 cron 的配置和说明
建立源,当然要用 rsync ,不过这里并非直接使用,而是用的 Debian 官网提供的一段脚本,叫做 anonftpsync,加上 cron 作为定时任务做成的。
cron 是 Linux 下的计划任务工具,可以按每小时、每天、每星期、每月执行任务,支持多用户多设置,很是方便。往下看之前,确认你安装了 rsync,并且开启了 cron 守护程序。
下面说一下步骤:
首先,建立源目录。如果想放在 FTP 服务器上,应该建立在 FTP 目录里,比如:
mkdir /home/ftp/ubuntu
mkdir -p /home/ftp/ubuntu/project/trace/
#! /bin/sh -p
set -e
# EXCLUDE 是你要排除的文件和目录。
EXCLUDE="--exclude *alpha.deb \
--exclude *alpha.udeb \
--exclude binary-alpha/ \
--exclude disks-alpha/ \
--exclude *-alpha.gz \
--exclude installer-alpha/ \
--exclude binary-arm/ \
--exclude *arm.deb \
--exclude *arm.udeb \
--exclude disks-arm/ \
--exclude *-arm.gz \
--exclude installer-arm/ \
--exclude binary-m68k/ \
--exclude *m68k.deb \
--exclude *m68k.udeb \
--exclude disks-m68k/ \
--exclude *-m68k.gz \
--exclude installer-m68k/ \
--exclude binary-hppa/ \
--exclude *hppa.deb \
--exclude *hppa.udeb \
--exclude disks-hppa/ \
--exclude *-hppa.gz \
--exclude installer-hppa/ \
--exclude binary-ia64/ \
--exclude *ia64.deb \
--exclude *ia64.udeb \
--exclude disks-ia64/ \
--exclude *-ia64.gz \
--exclude installer-ia64/ \
--exclude binary-mips/ \
--exclude *mips.deb \
--exclude *mips.udeb \
--exclude disks-mips/ \
--exclude *-mips.gz \
--exclude installer-mips/ \
--exclude binary-mipsel/ \
--exclude *mipsel.deb \
--exclude *mipsel.udeb \
--exclude disks-mipsel/ \
--exclude *-mipsel.gz \
--exclude installer-mipsel/ \
--exclude binary-s360/ \
--exclude *s360.deb \
--exclude *s360.udeb \
--exclude disks-s360/ \
--exclude *-s360.gz \
--exclude installer-s360/ \
--exclude binary-s390/ \
--exclude *s390.deb \
--exclude *s390.udeb \
--exclude disks-s390/ \
--exclude *-s390.gz \
--exclude installer-s390/ \
--exclude binary-sh/ \
--exclude *sh.deb \
--exclude *sh.udeb \
--exclude disks-sh/ \
--exclude *-sh.gz \
--exclude installer-sh/ \
--exclude binary-sparc/ \
--exclude *sparc.deb \
--exclude *sparc.udeb \
--exclude disks-sparc/ \
--exclude *-sparc.gz \
--exclude installer-sparc/ \
--exclude /Debian-1.3* \
--exclude /Debian3.1* \
--exclude local/ \
--exclude stable/ \
--exclude slink-proposed-updates/ \
--exclude slink/ \
--exclude bo/ \
--exclude bo-unstable/ \
--exclude bo-updates/ \
--exclude binary-hurd-i386/ \
--exclude *hurd-i386.deb \
--exclude *hurd-i386.udeb \
--exclude disks-hurd-i386/ \
--exclude *-hurd-i386.gz \
--exclude installer-hurd-i386/ \
--exclude binary-powerpc/ \
--exclude *powerpc.deb \
--exclude *powerpc.udeb \
--exclude disks-powerpc/ \
--exclude *-powerpc.gz \
--exclude installer-powerpc/ "
#--exclude /contrib/ --exclude /non-free/ --exclude source/\
# --exclude Incoming/ \
#######################################
# TO 是目标目录
TO=/home/ftp/ubuntu
# 以下两个合起来就是源地址: debian.ustc.edu.cn/ubuntu/
# 这里设置同步的服务器域名
RSYNC_HOST=debian.ustc.edu.cn
# 这里是同步服务器上源所在的目录
RSYNC_DIR=ubuntu/
LOCK="${TO}/Archive-Update-in-Progress-`hostname -f`"
# Get in the right directory and set the umask to be group writable
#
cd $HOME
umask 002
# Check to see if another sync is in progress
if lockfile -! -l 43200 -r 0 "$LOCK"; then
echo `hostname` is unable to start rsync, lock file exists
exit 1
fi
trap "rm -f $LOCK > /dev/null 2>&1" exit
set +e
#result=1
#while (( $result != 0 )) ; do
rsync -rltv --progress --delete \
--exclude "Archive-Update-in-Progress-`hostname -f`" \
--exclude "project/trace/`hostname -f`" \
$EXCLUDE \
$RSYNC_HOST::$RSYNC_DIR $TO > ${HOME}/log/rsync.log 2>&1
#result=$?
#done
date -u > "${TO}/project/trace/`hostname -f`"
savelog ${HOME}/log/rsync.log > /dev/null 2>&1
chmod +x anonftpsync
chmod 755 /home/ftp/ubuntu
crontab -e
00 2 * * * /usr/local/bin/anonftpsync
crontab -l
/etc/init.d/cron restart
/etc/rc.d/crond restart
可以看到,建立一个 Ubuntu/Debian 源并没有如何麻烦,这不得不归功于 linux 下工具和脚本的强大,呵呵~
如果有教育网的同学,可以加这个源,现在还在同步中,呵呵~每天从中国科技大学同步一次。从这里下载源列表:
ftp://tofree.org/sources.list/
Linux下统计代码行数的方法
我们编程时常常想统计一下自己写过多少行代码了,这时候该怎么办呢?
虽然Vim等编辑器中有代码行数显示,但是不能一个个打开然后加起来吧?
这个时候需要用到wc这个工具,呵呵,别看名字不怎么样,功能可是很强大的哦。
用法:
当前目录下:
wc -l *.c *.h
当前目录及子目录:
find . -name *.c |xargs wc -l find . -name *.cpp | xargs wc -l find . -name *.h |xargs wc -l
很方便吧?
PS:我的Cugb Linker原来还不到600行……努力!
使用 screen 管理你的远程会话(转载)
原文:http://blog.zhangjianfeng.com/article/718
你是不是经常需要 SSH 或者 telent 远程登录到 Linux 服务器?你是不是经常为一些长时间运行的任务而头疼,比如系统备份、ftp 传输等等。通常情况下我们都是为每一个这样的任务开一个远程终端窗口,因为他们执行的时间太长了。必须等待它执行完毕,在此期间可不能关掉窗口或者断开连 接,否则这个任务就会被杀掉,一切半途而废了。
让我们来看看为什么关掉窗口/断开连接会使得正在运行的程序死掉。
在Linux/Unix中,有这样几个概念:
- 进程组(process group):一个或多个进程的集合,每一个进程组有唯一一个进程组ID,即进程组长进程的ID。
- 会话期(session):一个或多个进程组的集合,有唯一一个会话期首进程(session leader)。会话期ID为首进程的ID。
- 会话期可以有一个单独的控制终端(controlling terminal)。与控制终端连接的会话期首进程叫做控制进程(controlling process)。当前与终端交互的进程称为前台进程组。其余进程组称为后台进程组。
根据POSIX.1定义:
- 挂断信号(SIGHUP)默认的动作是终止程序。
- 当终端接口检测到网络连接断开,将挂断信号发送给控制进程(会话期首进程)。
- 如果会话期首进程终止,则该信号发送到该会话期前台进程组。
- 一个进程退出导致一个孤儿进程组中产生时,如果任意一个孤儿进程组进程处于STOP状态,发送SIGHUP和SIGCONT信号到该进程组中所有进程。
因此当网络断开或终端窗口关闭后,控制进程收到SIGHUP信号退出,会导致该会话期内其他进程退出。
我们来看一个例子。打开两个SSH终端窗口,在其中一个运行top命令。
[root@tivf09 root]# top |
在另一个终端窗口,找到top的进程ID为5180,其父进程ID为5128,即登录shell。
[root@tivf09 root]# ps -ef|grep top root 5180 5128 0 01:03 pts/0 00:00:02 top root 5857 3672 0 01:12 pts/2 00:00:00 grep top |
使用pstree命令可以更清楚地看到这个关系:
[root@tivf09 root]# pstree -H 5180|grep top |-sshd-+-sshd---bash---top |
使用ps-xj命令可以看到,登录shell(PID 5128)和top在同一个会话期,shell为会话期首进程,所在进程组PGID为5128,top所在进程组PGID为5180,为前台进程组。
[root@tivf09 root]# ps -xj|grep 5128 5126 5128 5128 5128 pts/0 5180 S 0 0:00 -bash 5128 5180 5180 5128 pts/0 5180 S 0 0:50 top 3672 18095 18094 3672 pts/2 18094 S 0 0:00 grep 5128 |
关闭第一个SSH窗口,在另一个窗口中可以看到top也被杀掉了。
[root@tivf09 root]# ps -ef|grep 5128 root 18699 3672 0 04:35 pts/2 00:00:00 grep 5128 |
如果我们可以忽略SIGHUP信号,关掉窗口应该就不会影响程序的运行了。nohup命令可以达到这个目的,如果程序的标准输出/标准错误是终 端,nohup默认将其重定向到nohup.out文件。值得注意的是nohup命令只是使得程序忽略SIGHUP信号,还需要使用标记&把它放在后台运行。
nohup |
虽然nohup很容易使用,但还是比较”简陋”的,对于简单的命令能够应付过来,对于复杂的需要人机交互的任务就麻烦了。
其实我们可以使用一个更为强大的实用程序screen。流行的Linux发行版(例如Red Hat Enterprise Linux 4)通常会自带screen实用程序,如果没有的话,可以从GNU screen的官方网站下载。
[root@tivf06 ~]# rpm -qa|grep screen xscreensaver-4.18-5.rhel4.11 screen-4.0.2-5 |
开始使用Screen
简单来说,Screen是一个可以在多个进程之间多路复用一个物理终端的窗口管理器。Screen中有会话的概念,用户可以在一个screen会话 中创建多个screen窗口,在每一个screen窗口中就像操作一个真实的telnet/SSH连接窗口那样。在screen中创建一个新的窗口有这样 几种方式:
1.直接在命令行键入screen命令
[root@tivf06 ~]# screen |
Screen将创建一个执行shell的全屏窗口。你可以执行任意shell程序,就像在ssh窗口中那样。在该窗口中键入exit退出该窗口,如果这是该screen会话的唯一窗口,该screen会话退出,否则screen自动切换到前一个窗口。
2.Screen命令后跟你要执行的程序。
[root@tivf06 ~]# screen vi test.c |
Screen创建一个执行vi test.c的单窗口会话,退出vi将退出该窗口/会话。
3.以上两种方式都创建新的screen会话。我们还可以在一个已有screen会话中创建新的窗口。在当前screen窗口中键入C-a c,即Ctrl键+a键,之后再按下c键,screen 在该会话内生成一个新的窗口并切换到该窗口。
screen还有更高级的功能。你可以不中断screen窗口中程序的运行而暂时断开(detach)screen会话,并在随后时间重新连接(attach)该会话,重新控制各窗口中运行的程序。例如,我们打开一个screen窗口编辑/tmp/abc文件:
[root@tivf06 ~]# screen vi /tmp/abc |
之后我们想暂时退出做点别的事情,比如出去散散步,那么在screen窗口键入C-a d,Screen会给出detached提示:
暂时中断会话
半个小时之后回来了,找到该screen会话:
[root@tivf06 ~]# screen -ls There is a screen on: 16582.pts-1.tivf06 (Detached) 1 Socket in /tmp/screens/S-root. |
重新连接会话:
[root@tivf06 ~]# screen -r 16582 |
看看出现什么了,太棒了,一切都在。继续干吧。
你可能注意到给screen发送命令使用了特殊的键组合C-a。这是因为我们在键盘上键入的信息是直接发送给当前screen窗口,必须用其他方式 向screen窗口管理器发出命令,默认情况下,screen接收以C-a开始的命令。这种命令形式在screen中叫做键绑定(key binding),C-a叫做命令字符(command character)。
可以通过C-a ?来查看所有的键绑定,常用的键绑定有:
| C-a ? | 显示所有键绑定信息 |
|---|---|
| C-a w | 显示所有窗口列表 |
| C-a C-a | 切换到之前显示的窗口 |
| C-a c | 创建一个新的运行shell的窗口并切换到该窗口 |
| C-a n | 切换到下一个窗口 |
| C-a p | 切换到前一个窗口(与C-a n相对) |
| C-a 0..9 | 切换到窗口0..9 |
| C-a a | 发送 C-a到当前窗口 |
| C-a d | 暂时断开screen会话 |
| C-a k | 杀掉当前窗口 |
| C-a [ | 进入拷贝/回滚模式 |
Screen常用选项
使用键绑定C-a ?命令可以看到, 默认的命令字符(Command key)为C-a,转义C-a(literal ^a)的字符为a:
Screen 常用选项
因为screen把C-a看作是screen命令的开始,所以如果你想要screen窗口接收到C-a字符,就要输入C-a a。Screen也允许你使用-e选项设置自己的命令字符和转义字符,其格式为:
-exy x为命令字符,y为转义命令字符的字符
下面命令启动的screen会话指定了命令字符为C-t,转义C-t的字符为t,通过C-t ?命令可以看到该变化。
自定义命令字符和转义字符
[root@tivf18 root]# screen -e^tt |
其他常用的命令选项有:
| -c file | 使用配置文件file,而不使用默认的$HOME/.screenrc |
|---|---|
| -d|-D [pid.tty.host] | 不开启新的screen会话,而是断开其他正在运行的screen会话 |
| -h num | 指定历史回滚缓冲区大小为num行 |
| -list|-ls | 列出现有screen会话,格式为pid.tty.host |
| -d -m | 启动一个开始就处于断开模式的会话 |
| -r sessionowner/ [pid.tty.host] | 重新连接一个断开的会话。多用户模式下连接到其他用户screen会话需要指定sessionowner,需要setuid-root权限 |
| -S sessionname | 创建screen会话时为会话指定一个名字 |
| -v | 显示screen版本信息 |
| -wipe [match] | 同-list,但删掉那些无法连接的会话 |
下例显示当前有两个处于detached状态的screen会话,你可以使用screen -r
[root@tivf18 root]# screen -ls There are screens on: 8736.pts-1.tivf18 (Detached) 8462.pts-0.tivf18 (Detached) 2 Sockets in /root/.screen. [root@tivf18 root]# screen -r 8736 |
如果由于某种原因其中一个会话死掉了(例如人为杀掉该会话),这时screen -list会显示该会话为dead状态。使用screen -wipe命令清除该会话:
[root@tivf18 root]# kill -9 8462 [root@tivf18 root]# screen -ls There are screens on: 8736.pts-1.tivf18 (Detached) 8462.pts-0.tivf18 (Dead ???) Remove dead screens with 'screen -wipe'. 2 Sockets in /root/.screen. [root@tivf18 root]# screen -wipe There are screens on: 8736.pts-1.tivf18 (Detached) 8462.pts-0.tivf18 (Removed) 1 socket wiped out. 1 Socket in /root/.screen. [root@tivf18 root]# screen -ls There is a screen on: 8736.pts-1.tivf18 (Detached) 1 Socket in /root/.screen. [root@tivf18 root]# |
-d -m 选项是一对很有意思的搭档。他们启动一个开始就处于断开模式的会话。你可以在随后需要的时候连接上该会话。有时候这是一个很有用的功能,比如我们可以使用它调试后台程序。该选项一个更常用的搭配是:-dmS sessionname
启动一个初始状态断开的screen会话:
[root@tivf06 tianq]# screen -dmS mygdb gdb execlp_test |
连接该会话:
[root@tivf06 tianq]# screen -r mygdb |
先来看看如何使用screen解决SIGHUP问题,比如现在我们要ftp传输一个大文件。如果按老的办法,SSH登录到系统,直接ftp命令开始 传输,之后。。如果网络速度还可以,恭喜你,不用等太长时间了;如果网络不好,老老实实等着吧,只能传输完毕再断开SSH连接了。让我们使用screen 来试试。
[root@tivf18 root]# screen |
在screen shell窗口中输入ftp命令,登录,开始传输。不愿意等了?OK,在窗口中键入C-a d:
管理你的远程会话
然后。。退出SSH登录?随你怎样,只要别杀掉screen会话。
是不是很方便?更进一步,其实我们可以利用screen这种功能来管理你的远程会话,保存你所有的工作内容。你是不是每次登录到系统都要开很多窗 口,然后每天都要重复打开关闭这些窗口?让screen来帮你”保存”吧,你只需要打开一个ssh窗口,创建需要的screen窗口,退出的时候C-a d”保存”你的工作,下次登录后直接screen -r
最好能给每个窗口起一个名字,这样好记些。使用C-a A给窗口起名字。使用C-a w可以看到这些窗口名字,可能名字出现的位置不同。使用putty:
putty
更多Screen功能
Screen提供了丰富强大的定制功能。你可以在Screen的默认两级配置文件/etc/screenrc和$HOME/.screenrc中指 定更多,例如设定screen选项,定制绑定键,设定screen会话自启动窗口,启用多用户模式,定制用户访问权限控制等等。如果你愿意的话,也可以自 己指定screen配置文件。
以多用户功能为例,screen默认是以单用户模式运行的,你需要在配置文件中指定multiuser on 来打开多用户模式,通过acl*(acladd,acldel,aclchg…)命令,你可以灵活配置其他用户访问你的screen会话。更多配置文件内 容请参考screen的man页。
CMake 项目卸载方法
CMake 默认不提供 uninstall 这个 target,想要的话,输入:
xargs rm < install_manifest.txt
对于不修改配置的项目足够了。
manifest.txt是CMake生成的安装文件列表。

