下一页 上一页 目录

4. 不同 Shell 的示例

下面我们提供了一系列针对一些更常见 Shell 的示例。我们从 zsh 开始,因为它提供了一些工具,使我们的工作更加容易。然后我们将逐步介绍越来越困难的示例。

在所有示例中,我们都测试了环境变量 $TERM,以确保我们仅将转义符应用于 xterm。我们测试 $TERM=xterm*;通配符是因为某些变体(例如 rxvt)可能会设置 $TERM=xterm-color

我们应该对 C Shell 的衍生版本(如 tcshcsh)做额外的说明。在 C Shell 中,未定义的变量是致命错误。因此,在测试变量 $TERM 之前,必须先测试其是否存在,以免破坏非交互式 Shell。为了实现这一点,您必须将下面的示例包装在类似如下的内容中:

  if ($?TERM) then
      ...
  endif
(我们认为这仅仅是不使用 C Shell 的众多原因之一。请参阅Csh 编程被认为是有害的,以获得有用的讨论)。

下面的示例应通过将它们插入到适当的 Shell 初始化文件中来使用;即在启动时由交互式 Shell 加载的文件。在大多数情况下,这被称为类似 .shellrc 的名称(例如 .zshrc.tcshrc 等)。

4.1 zsh

zsh 提供了一些函数和扩展,我们将使用它们

precmd ()   a function which is executed just before each prompt
chpwd ()    a function which is executed whenever the directory is changed
\e          escape sequence for escape (ESC)
\a          escape sequence for bell (BEL)
%n          expands to $USERNAME
%m          expands to hostname up to first '.'
%~          expands to directory, replacing $HOME with '~'
还有许多其他的扩展可用:请参阅 zshmisc 的 man 手册。

因此,以下命令会将 xterm 标题设置为“username@hostname: directory

case $TERM in
    xterm*)
        precmd () {print -Pn "\e]0;%n@%m: %~\a"}
        ;;
esac
这也可以通过使用 chpwd() 而不是 precmd() 来实现。print 内置命令的工作方式类似于 echo,但允许我们访问 % 提示符转义符。

4.2 tcsh

tcsh 具有一些类似于 zsh 的函数和扩展

precmd ()   a function which is executed just before each prompt
cwdcmd ()   a function which is executed whenever the directory is changed
%n          expands to username
%m          expands to hostname
%~          expands to directory, replacing $HOME with '~'
%#          expands to '>' for normal users, '#' for root users
%{...%}     includes a string as a literal escape sequence

不幸的是,没有像 zshprint 命令那样的等效命令允许我们在标题字符串中使用提示符转义符,因此我们能做的最好的事情是使用 Shell 变量(在 ~/.tcshrc 中)

switch ($TERM)
    case "xterm*":
        alias precmd 'echo -n "\033]0;${HOST}:$cwd\007"'
        breaksw
endsw
但是,这给出了目录的完整路径,而不是使用 ~。相反,您可以将字符串插入到提示符中
switch ($TERM)
    case "xterm*":
        set prompt="%{\033]0;%n@%m:%~\007%}tcsh%# "
        breaksw
    default:
        set prompt="tcsh%# "
        breaksw
endsw
这将设置提示符为 “tcsh% ”,并将 xterm 标题和图标设置为 “username@hostname: directory”。请注意,“%{...%}” 必须放在转义序列周围(并且不能是提示符中的最后一个项目:有关详细信息,请参阅 tcsh 的 man 手册)。

4.3 bash

bash 提供了一个变量 $PROMPT_COMMAND,其中包含在提示符之前执行的命令。此示例将标题设置为 username@hostname: directory

PROMPT_COMMAND='echo -ne "\033]0;${USER}@${HOSTNAME}: ${PWD}\007"'
其中 \033ESC 的字符代码,\007BEL 的字符代码。

请注意,这里的引号非常重要:变量在 "..." 中展开,而在 '...' 中不展开。因此,$PROMPT_COMMAND 被设置为未展开的值,但是当使用 $PROMPT_COMMAND 时,"..." 内的变量会被展开。

但是,$PWD 会生成完整的目录路径。如果我们想使用 ~ 简写,我们需要将转义字符串嵌入到提示符中,这允许我们利用 Shell 提供的以下提示符扩展

\u          expands to $USERNAME
\h          expands to hostname up to first '.'
\w          expands to directory, replacing $HOME with '~'
\$          expands to '$' for normal users, '#' for root
\[...\]     embeds a sequence of non-printing characters

因此,以下命令会生成 bash$ 的提示符,以及 username@hostname: directory 的 xterm 标题

case $TERM in
    xterm*)
        PS1="\[\033]0;\u@\h: \w\007\]bash\\$ "
        ;;
    *)
        PS1="bash\\$ "
        ;;
esac
请注意 \[...\] 的使用,它告诉 bash 在计算提示符的宽度时忽略非打印控制字符。否则,行编辑命令在放置光标时会感到困惑。

4.4 ksh

ksh 在函数和扩展方面提供的很少,因此我们必须将转义字符串插入到提示符中,以使其动态更新。此示例生成 username@hostname: directory 的标题和 ksh$ 的提示符。

case $TERM in
    xterm*)
        HOST=`hostname`
        PS1='^[]0;${USER}@${HOST}: ${PWD}^Gksh$ '
        ;;
    *)
        PS1='ksh$ '
        ;;
esac
但是,$PWD 会生成完整的目录路径。我们可以使用 ${...##...} 构造从目录中删除 $HOME/ 的前缀。我们还可以使用 ${...%%...} 截断主机名
HOST=`hostname`
HOST=${HOST%%.*}
PS1='^[]0;${USER}@${HOST}: ${PWD##${HOME}/}^Gksh$ '
请注意,提示符字符串中的 ^[^GESCBEL 的单个字符(可以使用 C-q ESCC-q C-g 在 emacs 中输入)。

4.5 csh

这在 csh 中确实非常困难,最终我们做了类似以下的事情

switch ($TERM)
    case "xterm*":
        set host=`hostname`
        alias cd 'cd \!*; echo -n "^[]0;${user}@${host}: ${cwd}^Gcsh% "'
        breaksw
    default:
        set prompt='csh% '
        breaksw
endsw
在这里,我们不得不别名化 cd 命令来完成发送转义序列的工作。请注意,字符串中的 ^[^GESCBEL 的单个字符(可以使用 C-q ESCC-q C-g 在 emacs 中输入)。

注意:在某些系统上,可以使用 hostname -s 来获取短主机名,而不是完全限定的主机名。某些使用符号链接目录的用户可能会发现 `pwd` (反引号运行 pwd 命令)比 $cwd 提供更准确的路径。


下一页 上一页 目录