免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 2187 | 回复: 0
打印 上一主题 下一主题

对话 UNIX: 极限 shell 改造 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2012-01-17 17:41 |只看该作者 |倒序浏览
无论您开什么车,您一定会喜欢高速的大马力汽车。没有什么车比配备五轮辐镀镁轮毂、宽轮胎、黑色油漆、大量镀铬部件和强劲的大马力引擎的 1969 年产 Dodge Charger 更给力了。它是一部杰作,就像 Rodin 的思考者一样,是一部经典之作。
UNIX® shell 也是一部经典之作。只要经过一番改造,它也可以像高速的大马力汽车一样强劲有力。您可以将这个改造过程称为 “极限 shell 改造”。我觉得这很酷!
它由活动部件组成
在闪动的提示符背后,您的 shell(比如 Bash、Z shell 或其他 shell)有许多活动部件,您可以增强、改进和调整它们。以下是对这些部件的总结(其中许多已在前面的专栏文章中详细讨论过):
  • 别名(alias)是缩写的命令名和命令行短语。例如,命令 alias ll 'ls -hlt' 将一个常用的命令行缩减为两个字母,从而使要输入和要记住的东西变得更少。别名通常只是单纯的缩写。但是,与 shell 脚本或 shell 函数一样,别名也可以接受参数。命令 alias print 'lpr -h -Pps5 \!*' 可以将 \!* 替换为命令行参数。因此,print manual.ps schematic.ps form.ps 会展开为 lpr -h -Pps5 manual.ps schematic.ps form.ps
  • 环境变量跨命令(甚至是生成新进程的命令)保存设置。根据惯例,一些环境变量有特殊含义:命令和应用程序认为 PRINTER 表示首选输出设备,而 EDITOR 和 PAGER 分别表示用来修改和显示文本的文本编辑器和查看器。其他环境变量与不同的实用程序有关。PS1 就是这样一个例子,它告诉 shell 将显示哪些内容作为最初提示。另一个重要的环境变量是 shell 的 PATH,它列出了搜索可执行文件的目录。(要想了解特定应用程序或命令中可以识别哪些环境变量,请参阅其手册页中的 "Environment variables" 部分。)
  • 函数也可以从命令行调用,它们填补了别名与完全成熟的脚本之间的空缺。例如,如果需要操纵参数或应用逻辑,别名很可能不够用;但是,使用完整的脚本可能太过浪费。因此可以通过组合使用函数来实现累积的效果。创建函数需要一定的编程经验,但是并不不是很麻烦。
  • shell 选项控制了 shell 的行为。shell 选项通常因 shell 而异,功能丰富的 shell(比如 Bash 或 Z shell)可能有数百个可调整参数。(Z shell 有专门对配置选项进行解释的手册页 zshoptions。)例如,如果已经启用了 Z shell 选项pushd_ignore_dupspushd 就不会将已存在的目录压入目录堆栈。您可以花几小时研究选项,寻找想要的组合,然后执行 set(Bash) 或 setopt 并将输出重定向到某个文件中。可以将捕捉到的部分或所有设置复制到启动文件中,这样就可以在每次打开 shell 时重建自己的工作空间。
除了这些部件之外,还可以改变 shell 的外观。美元符号 ($) 提示符可以显示为不同的颜色,以反映当前工作目录,甚至是天气情况。只要可以用命令捕捉到信息,就可以将它们显示在提示符中。

修改提示符
与 shell 中的其他操作一样,环境变量可以控制每次 shell 显示提示符时应显示的内容。与命令行本身一样,可以在呈现提示符内容时对变量 PS1(或 "prompt string level 1")进行解释。PS1 可以包含其他 shell 和环境变量、置换命令运算(通过反引号)和特殊的字面值。下面是一个简单的示例:
$ export PS1="\u@\h \w >"strike@nostromo ~ > whoami; hostname; pwdstrikenostromo/home/strikestrike@nostromo ~ >

最初,提示符是简单的 $ 符号。如果将环境变量 PS1 设置(使用 export 而不是 set)为 \u@\h \w >,则会显示您的用户名 (\u)、字面值 @、主机名 (\h)、当前工作目录 (\w) 和字面字符串 >
其他特殊的字面值包括 \t(采用 24 小时制的时间格式)、\d(采用周、月、日格式的日期)和 \!(shell 历史记录编号)。如果 shell 窗口打开的时间较长,可以用 !nnn 快速重复前面的命令,其中的 nnn 是命令提示符中显示的编号。
strike@nostromo ~ > export PS1="\! $ "776 $ find . -name ......999 $ !776find . -name ...1000 $

当您的行为类似于超级用户(即 root 用户)时,shell 提示符会变成 #,您可能对此感到惊奇。默认情况下,标准的提示符实际上是特殊操作符 \$。如果您的有效用户 ID 是 0,则会使用 # 作为提示符;否则会使用 $
还有用来改变颜色的缩写。下面是一个示例:
strike@nostromo ~ > export PS1='$ '$ blue='\e[0;34m'$ none='\e[m'$ export PS1="$blue\u@\h$none\w>"<span style="color: blue;">strike@nostromo </span>~ ><br />

十分笨拙的缩写 \e[0;34m 表示可以启用蓝色。\e[m 可以将显示颜色恢复为 shell 窗口的默认颜色。这两个编码均放在单引号内,以防止 shell 篡改有特殊含义的字符。这个示例还说明可以在提示符中使用变量。在解释命令行时,会展开变量 bluenone,提示符被设置为展开变量而生成的字符串。如果希望在每次显示提示符时都动态展开变量,则必须在设置提示符时对它的解释进行转义。请参见以下示例:
<span style="color: blue;">strike@nostromo     </span>~ >export PS1="\$somevar $ "$ somevar="hello"hello $

\$somevar 可以对美元符号进行转义,避免在设置提示符的命令中对该变量进行解释,而是在显示提示符时对其进行解释。如果其他命令改变了 somevar 的值,提示符将显示为新的值。
正如前面提到的,还可以在提示符下调用任何命令或函数。只需使用反引号 (``)。例如,在使用 Ruby Version Manager 在不同的 Ruby 语言版本和解释器之间切换时,您可能想知道当前使用了哪种 Ruby 二进制代码。有两种实现此操作的方法:
hello $ export PS1="(`which ruby`) \w $ "(/Users/strike/.rvm/rubies/ruby-1.9.2-p0/bin/ruby) ~ $

第一种方法使用 which 在当前的 PATH 中寻找第一个 Ruby 可执行文件。后一种方法实现相同的目标,它展示了置换命令运算可以有多么复杂。如果将提示符设置为以下字符串:
"(`rvm info | grep 'ruby:' | grep bin | cut -f2 -d: | tr \\" ' '`)"

会得到相同的结果,尽管没必要采用这么复杂的方式。
顺便说一句,您可能想知道 PS1 为什么是 "prompt string level 1"。是否存在其他提示符级别?是的,存在针对 PS2、PS3 和 PS4 的环境变量,当打开新的块时,会出现这些提示符。下面是一个示例:
$ for i in [A-Z]*>

输入 for i in [A-Z]* 并按回车之后,shell 会显示 PS2 提示符(默认提示符是 >),这表明您目前位于 for 循环主体中。换句话说,您现在 “嵌套” 在循环中,处于更深的一级。如果用 done 结束循环,第一级提示符会重新出现。
$ for i in [A-Z]*> do> echo $i> doneGemfileGemfile.lockREADMERakefile$

实际上,只要在前面的提示符中没有完成命令行,就会出现新提示符。这解释了不匹配的单引号或双引号会导致出现新提示符的原因。shell 会提示您继续输入前面已经开始的命令行。
在提示符中嵌入信息是跟踪状态(比如当前主机、工作目录等等)的好方法。创建您喜欢的提示符之后,将 shell 启动文件分发给您的所有帐号。如果您与大多数现代用户一样,那么您的屏幕上会有许多远程 shell 窗口,提示符可以帮助您区分它们。可以创建根据主机改变提示符颜色的函数。

modder 和 rodder
一些用户将定制 shell 当作一种消遣,您可以在网上找到很多这方面的灵感和源代码。有两个软件包非常值得一提:Oh My Z Shell! 和 Bash It!。前者适用于 Z shell,后者适用于 Bash。它们都是 shell 修改的集合,包括一些补充、主题(颜色和提示符)、函数和现成的 "dot" 文件。它们都是开放源码的,可以从 github 获得它们。让我们来试一下 Oh My Z Shell!(或简称为 OMZ!)。要想使用它,您必须安装 Z shell 4.3.9 或更高版本。
可以使用 wget 安装这个包,并自动将您的 shell 改为 Z shell,参见清单 1。

清单 1. 安装 shell 并将它改为 Z shell
$ wget http://github.com/robbyrussell/o ... er/tools/install.sh -O - | sh
...
Cloning Oh My Zsh...
Cloning into /Users/strike/.oh-my-zsh...
remote: Counting objects: 1312, done.
remote: Compressing objects: 100% (750/750), done.
remote: Total 1312 (delta 796), reused 944 (delta 520)
Receiving objects: 100% (1312/1312), 153.63 KiB, done.
Resolving deltas: 100% (796/796), done.
Looking for an existing zsh config...
Using the Oh My Zsh template file and adding it to ~/.zshrc
Copying your current PATH and adding it to the end of ~/.zshrc for you.
Time to change your default shell to zsh!
Changing shell for strike.
Password for strike:
chsh: /usr/bin/env zsh: non-standard shell

还可以手工安装这个工具包。如果您在运行另一种 shell,只是想试试 Z shell,那么手工安装可能会更好。请使用 Git 复制这个工具包,然后运行 zsh
$ git clone git://github.com/robbyrussell/oh-my-zsh.git ~/.oh-my-zsh$ cp ~/.oh-my-zsh/templates/zshrc.zsh-template ~/.zshrc$ zsh

您应该会看到与图 1 相似的屏幕和提示符。OMZ! 的默认主题称为 "robbyrussell",由 OMZ! 的管理者命名。您可以将它更改为 ~/.oh-my-zsh/themes 中列出的任何主题。更改主题的方法是,打开 ~/.zshrc 文件,将 ZSH_THEME 变量设置为主题文件的基本名称。例如,要想使用 cloud.zsh-theme,则应该设置 ZSH_THEME=cloud

图 1. 更改 shell 的主题

您可能会注意到,许多主题的输出状态信息显示在提示符中和提示符的最右边。例如,Clean 主题在最右边输出当前时间。与硬件屏幕不同,屏幕模拟器的底部通常没有状态条,但是可以使用提示符右边的区域提供动态反馈。还记得可以在提示符中使用 \e[ 编码设置颜色吗?有一组这样的 “转义” 可以将光标移动到窗口中的不同位置。另外,目前的 UNIX 系统并没有使用神秘的符号和数字,而是使用 tput 按名称或用途查找和产生转义。Z shell 使用这种方法提供 RPS1 和 RPS2,它们分别表示初始行和后续行右边的提示符。
除了通过主题控制颜色和提示符之外,OMZ! 还提供了一些插件,这些插件将同类的函数和特性集中在一起。例如,如果您使用 Git 进行源代码控制,可以启用 Git OMZ! 插件,它会在提示符中增加 Git 状态。请打开 ~/.zshrc 文件,然后编辑插件行,在其中包含 git>。现在,当切换到一个 Git 存储库时,提示符会反映该状态。例如,图 2 显示了 Clean 主题和一个存储库,其中有包含一些尚未提交的修改。

图 2. Clean 主题和存储库

提示显示了当前的分支 ("rubricmods" 和一个红色的 X,这表示当前存储库是 “脏的”,即已经修改了本地文件,但还没有提交。提交修改之后,X 会消失。Git 插件还为常用的 Git 命令组合创建别名,为 Git 选项提供上下文敏感的命令补全特性。来试一下:如果输入git branch,然后按 Tab 键,Git 插件就会列出可用的分支,以及用于 Mac OS X、Ruby on Rails 开发、MySQL 等的其他插件。一些插件很简单,可能只提供一个函数或几个别名;其他插件的功能可能更丰富。
Dirpersist 是说明 OMZ! 插件的用途的好例子。Dirpersist 跨 shell 调用存储并恢复目录堆栈,因此可以保留重要的状态,让您能够回到原来离开的位置继续工作。要使用它,请在 ~/.zshrc 文件中添加这个插件。这个插件的源代码很简单,参见清单 2。

清单 2. OMZ! 插件源代码
#!/bin/zsh
#
# Make the dirstack more persistent
#
# Add dirpersist to $plugins in ~/.zshrc to load
#
#
$zdirstore is the file used to persist the stack
zdirstore=~/.zdirstore
dirpersistinstall () {
if grep 'dirpersiststore' ~/.zlogout > /dev/null; then
  else
    if read -q \?"Would you like to set up your .zlogout file for
         use with dirpersist? (y/n) "; then
      echo "# Store dirs stack\n\
        # See ~/.oh-my-zsh/plugins/dirspersist.plugin.zsh\ndirpersiststore" >> ~/.zlogout
    else
      echo "If you don't want this message to appear, remove dirspersist from \$plugins"
    fi
  fi
}
dirpersiststore () {
  dirs -p | perl -e 'foreach (reverse <STDIN> {\
    chomp;s/([& ])/\\$1/g ;print "if [ -d $_ ]; then pushd -q $_; fi\n"}' > $zdirstore
}
dirpersistrestore () {
  if [ -f $zdirstore ]; then
    source $zdirstore
  fi
}
DIRSTACKSIZE=10
setopt autopushd pushdminus pushdsilent pushdtohome pushdignoredups
dirpersistinstall
dirpersistrestore
# Make popd changes permanent without having to wait for logout
alias popd="popd;dirpersiststore"

这个插件包含三个函数、几个 shell 选项和 popd 的别名(为每个弹出操作保留目录堆栈)。这个插件还对其环境进行初始化,创建存储目录堆栈的位置,通过修改 Z shell 退出文件 ~/.zlogout,在用户退出时保存目录堆栈。您应该可以看出,创建新的插件很容易,还可以围绕任何 shell 命令集来构建插件。
如果您喜欢 OMZ!,但是您使用的是 Bash shell,那么试一下 Bash It!。它的灵感来源于 OMZ!,具有相似的功能。Bash It! 还为 Subversion 和 nginx 提供了插件。

发动引擎吧!
研究 OMZ! 或 Bash It! 的内部机制,了解定制 shell 的一些技巧。通过在网上搜索 "dot files",还能找到一些充满智慧的、新奇的东西:许多 UNIX 爱好者在网上公开了他们的 shell 配置供他人借鉴。还有一点值得注意:应该对 dot 文件采用某种版本控制机制。有了存储库,您便可以更放心地试验各种修改和其他 shell。如果犯了错误,可以恢复以前的版本,还可以为不同的 shell 或场景保留相应的变体。shell 非常灵活,因为一种配置不一定适合所有场景。当您有了一套很酷的 dot 文件之后,请与别人分享。公开 dot 文件虽然不能使您成为《速度与激情》的下一部影片中的明星,但很可能会提高您在爱好者中的声誉。

关于作者
Martin Streicher 是一位 Ruby on Rails 的自由开发人员和 Linux Magazine 的前任主编。Martin 毕业于 Purdue University 并获得计算机科学学位,从 1986 年起他一直从事 UNIX 类系统的编程工作。他喜欢收集艺术品和玩具。




http://www.ibm.com/developerworks/cn/aix/library/au-spunix_shellmakeover/index.html


您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP