第 23 章 使用其他shell

本章内容

  • 理解dash shell
  • dash shell脚本编程
  • zsh shell介绍
  • zsh脚本编程

岁然bash shell是Linux发行版中最广泛使用的shell,但它并不是唯一的选择。现在你已经了解了标准的Linux bash shell,知道了能用它做什么,是时候看看Linux世界中的其他一些shell了。本章将会介绍另外两个你可能会碰到的shell,以及它们与bash shell有什么区别。

23.1 什么是 dash shell

Debian的dash shell的历史很有趣。它是ash shell的直系后代,而ash shell则是Unix系统上原来的Bourne shell的简化版本(参见第1章)。Kenneth Almquist为Unix系统开发了一个Bourne shell的简化版本,并将它命名为Almquist shell,缩写为ash。ash shell最早的版本体积极小、速度奇快, 但缺乏许多高级功能,比如命令行编辑或命令使用记录功能,这使它很难用作交互式shell。
23
NetBSD Unix操作系统移植了ash shell,直到今天依然将它用作默认shell。NetBSD开发人员对ash shell进行了定制,增加了一些新的功能,使它更接近Bourne shell。新功能包括使用emacs 和vi编辑器命令进行命令行编辑,利用历史命令来查看先前输入的命令。ash shell的这个版本也被FreeBSD操作系统用作默认登录shell。
Debian Linux发行版创建了它自己的ash shell版本(称作Debian ash,或dash)以供自用。dash复制了ash shell的NetBSD版本的大多数功能,提供了一些高级命令行编辑能力。
但令人不解的是,实际上dash shell在许多基于Debian的Linux发行版中并不是默认的shell。由于bash shell在Linux中的流行,大多数基于Debian的Linux发行版将bash shell用作普通登录shell, 而只将dash shell作为安装脚本的快速启动shell,用于安装发行版文件。
流行的Ubuntu发行版是例外。这经常让shell脚本程序员摸不清头脑,给Linux环境中运行shell 脚本带来了很多问题。Ubuntu Linux发行版将bash shell用作默认的交互shell,但将dash shell用作默认的/bin/sh shell。这个“特性”着实让shell脚本程序员一头雾水。
如第11章所述,每个shell脚本的起始行都必须声明脚本所用的shell。在bash shell脚本中,我们一直用下面的行。

#!/bin/bash

它会告诉shell使用位于/bin/bash的shell程序来执行脚本。在Unix世界中,默认shell一直是/bin/sh。许多熟悉Unix环境的shell脚本程序员会将这种用法带到他们的Linux shell脚本中。

#!/bin/sh

在大多数Linux发行版上,/bin/sh文件是链接到shell程序/bin/bash的一个符号链接(参见第3 章)。这样你就可以在无需修改的情况下,轻松地将为Unix Bourne shell设计的shell脚本移植到Linux环境中。
很遗憾,Ubuntu Linux发行版将/bin/sh文件链接到了shell程序/bin/dash。由于dash shell只含有原来Bourne shell中的一部分命令,这可能会(而且经常会)让有些shell脚本无法正确工作。
下一节将带你逐步了解dash shell的基础知识以及它跟bash shell的区别。如果你编写的bash shell脚本可能要在Ubuntu环境中运行,了解这些内容就尤其重要。

23.2 dash shell 的特性

尽管bash shell和dash shell都以Bourne shell为样板,但它们还是有一些差别的。在深入了解shell脚本编程特性之前,本节将会带你了解Debian dash shell的一些特性,以便让你熟悉dash shell 的工作方式。

23.2.1 dash 命令行参数

dash shell使用命令行参数来控制其行为。表23-1列出了命令行参数,并介绍了每个参数的用途。
表23-1 dash命令行参数

参 数 描 述
-a 导出分配给shell的所有变量
-c 从特定命令字符串中读取命令
-e 如果是非交互式shell的话,在有未经测试的命令失败时立即退出
-f 显示路径名通配符
-n 如果是非交互式shell的话,读取命令但不执行它们
-u 在尝试展开一个未设置的变量时,将错误消息写出到STDERR
-v 在读取输入时将输入写出到STDERR
-x 在执行命令时将每个命令写出到STDERR
-I 在交互式模式下,忽略输入中的EOF字符
-i 强制shell运行在交互式模式下
-m 启用作业控制(在交互式模式下默认开启)
-s 从STDIN读取命令(在没有指定文件参数时的默认行为)
-E 启用emacs命令行编辑器
-V 启用vi命令行编辑器

除了原先的ash shell的命令行参数外,Debian还加入了另外一些命令行参数。-E和-V命令行参数会启用dash shell特有的命令行编辑功能。
-E命令行参数允许使用emacs编辑器命令进行命令行文本编辑(参见第10章)。你可以使用所有的emacs命令来处理一行中的文本,其中会用到Ctrl和Meta组合键。
-V命令行参数允许使用vi编辑器命令进行命令行文本编辑(参见第10章)。这个功能允许用Esc键在普通模式和vi编辑器模式之间切换。当你在vi模式中时,可以用标准的vi编辑器命令(例如,x删除一个字符,i插入文本)。完成命令行编辑后,必须再次按下Esc键退出vi编辑器模式。

23.2.2 dash 环境变量

dash shell用相当多的默认环境变量来记录信息,你也可以创建自己的环境变量。本节将会介绍环境变量以及dash如何处理它们。

  1. 默认环境变量

dash环境变量跟bash环境变量很像(参见第6章)。这绝非偶然。别忘了dash shell和bash shell 都是Bourne shell的扩展版,两者都吸收了很多Bourne shell的特性。不过,由于dash的目标是简洁, 因此它的环境变量比bash shell少多了。在dash shell环境中编写脚本时要记住这点。
23
dash shell用set命令来显示环境变量。

$set
COLORTERM=''
DESKTOP_SESSION='default'
DISPLAY=':0.0'
DM_CONTROL='/var/run/xdmctl'
GS_LIB='/home/atest/.fonts'
HOME='/home/atest'
IFS='
'
KDEROOTHOME='/root/.kde'
KDE_FULL_SESSION='true'
KDE_MULTIHEAD='false'
KONSOLE_DCOP='DCOPRef(konsole-5293,konsole)'
KONSOLE_DCOP_SESSION='DCOPRef(konsole-5293,session-1)'
LANG='en_US'
LANGUAGE='en'
LC_ALL='en_US'
LOGNAME='atest'
OPTIND='1'
PATH='/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin'
PPID='5293'
PS1='$ '
PS2='> '
PS4='+ '
PWD='/home/atest'
SESSION_MANAGER='local/testbox:/tmp/.ICE-unix/5051'
SHELL='/bin/dash'
SHLVL='1'
TERM='xterm'
USER='atest'
XCURSOR_THEME='default'
_='ash'
$

这和你的默认dash shell环境很可能会不一样,因为不同的Linux发行版在登录时分配的默认环境变量不同。

  1. 位置参数

除了默认环境变量,dash shell还给命令行上定义的参数分配了特殊变量。下面是dash shell中用到的位置参数变量。

  • $0:shell的名称。
  • $n:第n个位置参数。
  • $*:含有所有参数内容的单个值,由IFS环境变量中的第一个字符分隔;没定义IFS的话, 由空格分隔。
  • $@:将所有的命令行参数展开为多个参数。
  • $#:位置参数的总数。
  • $?:最近一个命令的退出状态码。
  • $-:当前选项标记。
  • $$:当前shell的进程ID(PID)。
  • $!:最近一个后台命令的PID。

所有dash的位置参数都类似于bash shell中的位置参数。可以在shell脚本中使用位置参数,就和bash shell中的用法一样。

  1. 用户自定义的环境变量

dash shell还允许定义自己的环境变量。与bash一样,你可以在命令行上用赋值语句来定义新的环境变量。

$ testing=10 ; export testing
$ echo $testing
10
$

如果不用export命令,用户自定义的环境变量就只在当前shell或进程中可见。

警告 dash变量和bash变量之间有一个巨大的差异。dash shell不支持数组。这个小特性给高级shell脚本开发人员带来了各种问题。

23.2.3 dash 内建命令

跟bash shell一样,dash shell含有一组它能识别的内建命令。你可以在命令行界面上直接使用这些命令,或者将其放到shell脚本中。表23-2列出了dash shell的内建命令。
表23-2 dash shell内建命令

参 数 描 述
alias 创建代表文本字符串的别名字符串
bg 以后台模式继续执行指定的作业
cd 切换到指定的目录
echo 显示文本字符串和环境变量
eval 将所有参数用空格连起来①
exec 用指定命令替换shell进程
exit 终止shell进程
export 导出指定的环境变量,供子shell使用
fg 以前台模式继续执行指定的作业
getopts 从参数列表中中提取选项和参数
hash 维护并提取最近执行的命令及其位置的哈希表
pwd 显示当前工作目录
read 从STDIN读取一行并将其赋给一个变量
readonly 从STDIN读取一行并赋给一个只读变量
printf 用格式化字符串显示文本和变量
set 列出或设置选项标记和环境变量
shift 按指定的次数移动位置参数
test 测试一个表达式,成立的话返回0,不成立的话返回1
times 显示当前shell和所有shell进程的累计用户时间和系统时间
trap 在shell收到某个指定信号时解析并执行命令
type 解释指定的名称并显示结果(别名、内建、命令或关键字)
ulimit 查询或设置进程限制
umask 设置文件和目录的默认权限
unalias 删除指定的别名
unset 从导出的变量中删除指定的变量或选项标记
wait 等待指定的作业完成,然后返回退出状态码

你可能在bash shell中已经认识了上面的所有内建命令。dash shell支持许多和bash shell一样的内建命令。你会注意到其中没有操作命令历史记录或目录栈的命令。dash shell不支持这些特性。

23.3 dash 脚本编程

很遗憾,dash shell不能识别bash shell的所有脚本编程功能。为bash环境编写的脚本在dash shell中通常会运行失败,这给shell脚本程序员带来了很多痛苦。本节将介绍一些值得留意的差别,以便你的shell脚本能够在dash shell环境中正常运行。

23.3.1 创建 dash 脚本

到此你可能已经猜到了,为dash shell编写脚本和为bash shell编写脚本非常类似。一定要在脚本中指定要用哪个shell,保证脚本是用正确的shell运行的。
可以在shell脚本的第一行指定:

#!/bin/dash

还可以在这行指定shell命令行参数,23.2.1节介绍了这些参数。

23.3.2 不能使用的功能

很遗憾,由于dash shell只是Bourne shell功能的一个子集, bash shell脚本中的有些功能没法在dash shell中使用。这些通常被称作bash主义(bashism)。本节将简单总结你在bash shell脚本中习惯使用但在dash shell环境中没法工作的bash shell功能。

  1. 算术运算

第11章介绍了三种在bash shell脚本中进行数学运算的方法。

  • 使用expr命令:expr operation。
  • 使用方括号:$[ operation ]。
  • 使用双圆括号:$(( operation ))。

dash shell支持expr命令和双圆括号方法,但不支持方括号方法。如果有大量采用方括号形式的数学运算的话,这可能是个问题。
在dash shell脚本中执行算术运算的正确格式是用双圆括号方法。

$ cat test5b
#!/bin/dash
# testing mathematical operations
value1=10
value2=15
value3=$(( $value1 * $value2 ))
echo "The answer is $value3"
$ ./test5b
The answer is 150
$

现在shell可以正确执行这个计算了。

  1. test命令

虽然dash shell支持test命令,但你必须注意它的用法。bash shell版本的test命令与dash shell
版本的略有不同。
bash shell的test命令允许你使用双等号(==)来测试两个字符串是否相等。这是为了照顾习惯在其他编程语言中使用这种格式的程序员而加上去的。
但是,dash shell中的test命令不能识别用作文本比较的==符号,只能识别=符号。如果你在bash脚本中使用了==符号,就得将文本比较符号改成单个的等号。

$ cat test7
#!/bin/dash
# testing the = comparison
test1=abcdef
test2=abcdef
if [ $test1 = $test2 ]
then
  echo "They're the same!"
else
  echo "They're different"
fi
$ ./test7
They're the same!
$

仅这点bash主义就足以让shell程序员折腾几个小时了。

  1. function命令

第17章演示了如何在shell脚本中定义自己的函数。bash shell支持两种定义函数的方法:

  • 使用function()语句
  • 只使用函数名

dash shell不支持function语句。在dash shell中,你必须用函数名和圆括号定义函数。
如果你编写的脚本可能会用在dash环境中,就必须使用函数名来定义函数,决不能使用function()语句。

$ cat test10
#!/bin/dash
# testing functions
func1() {
  echo "This is an example of a function"
}
count=1
while [ $count -le 5 ]
do
  func1
  count=$(( $count + 1 ))
done
echo "This is the end of the loop"
func1
echo "This is the end of the script"
$ ./test10
This is an example of a function
This is an example of a function
This is an example of a function
This is an example of a function
This is an example of a function
This is the end of the loop
This is an example of a function
This is the end of the script
$

现在dash shell能够识别脚本中定义的函数并能在脚本中使用它了。

23.4 zsh shell

你可能会碰到的另一个流行的shell是Z shell(称作zsh)。zsh shell是由Paul Falstad开发的一个开源Unix shell。它汲取了所有现有shell的设计理念并增加了许多独到的功能,为程序员创建了一个无所不能的高级shell。
下面是zsh shell的一些独特的功能:

  • 改进的shell选项处理
  • shell兼容性模式
  • 可加载模块

在这些功能中,可加载模块是shell设计中最先进的功能。你在bash和dash shell中已经看到过了,每种shell都包含一组内建命令,这些命令无需借助外部工具程序就可以使用。内建命令的好处在于执行速度快。shell不必在运行命令前先加载一个工具程序。内建命令已经在内存中了,随时可用。
zsh shell提供了一组核心内建命令,并提供了添加额外命令模块(command module)的能力。每个命令模块都为特定场景提供了另外一组内建命令,比如网络支持和高级数学功能。可以只添加你觉得有用的模块。
这个功能提供了一个极佳的方式:在需要较小shell体积和较少命令时限制zsh shell的体积, 在需要更快执行速度时增加可用的内建命令数量。

23.5 zsh shell 的组成

本节将带你逐步了解zsh shell的基础知识,介绍可用的内建命令(或可以通过安装模块添加的命令)以及命令行参数和环境变量。

23.5.1 shell 选项

大多数shell采用命令行参数来定义shell的行为。zsh shell使用了一些命令行参数来定义shell 的操作,但大多数情况下它用选项来定制shell的行为。你可以在命令行上或在shell中用set命令设置shell选项。
表23-3列出了zsh shell可用的命令行参数。
表23-3 zsh shell命令行参数

参 数 描 述
-c 只执行指定的命令,然后退出
-i 作为交互式shell启动,提供一个命令行交互提示符
-s 强制shell从STDIN读取命令
-o 指定命令行选项

虽然这看起来像是一小组命令行参数,但-o参数有些容易让人误解。它允许你设置shell选项来定义shell的功能。到目前为止,zsh shell是所有shell中可定制性最强的。你可以更改很多shell 环境的特性。不同的选项可以分成以下几大类。

  • 更改目录:该选项用于控制cd命令和dirs命令如何处理目录更改。23
  • 补全:该选项用于控制命令补全功能。
  • 扩展和扩展匹配:该选项用于控制命令中文件扩展。
  • 历史记录:该选项用于控制命令历史记录。
  • 初始化:该选项用于控制shell在启动时如何处理变量和启动文件。
  • 输入输出:该选项用于控制命令处理。
  • 作业控制:该选项用于控制shell如何处理作业和启动作业。
  • 提示:该选项用于控制shell如何处理命令行提示符。
  • 脚本和函数:该选项用于控制shell如何处理shell脚本和定义函数。
  • shell仿真:该选项允许设置zsh shell来模拟其他类型shell行为。
  • shell状态:该选项用于定义启动哪种shell的选项。
  • zle:该选项用于控制zsh行编辑器功能。
  • 选项别名:可以用作其他选项别名的特殊选项。

既然有这么多种不同种类的shell选项,那你可以想象zsh shell实际上能够支持多少种选项。

23.5.2 内建命令

zsh shell的独到之处在于它允许扩展shell中的内建命令。这为许多不同的应用程序提供了大量的快速工具。
本节将会介绍核心内建命令以及在写作本书时可用的各种模块。

  1. 核心内建命令

zsh shell的核心包括一些你在其他shell中已经见到过的基本内建命令。表23-4列出了可用的内建命令。
表23-4 zsh核心内建命令

命令 描 述
alias 为命令和参数定义一个替代性名称autoload 将shell函数预加载到内存中以便快速访问bg 以后台模式执行一个作业
bindkey 将组合键和命令绑定到一起
builtin 执行指定的内建命令而不是同样名称的可执行文件
bye 跟exit相同
cd 切换当前工作目录
chdir 切换当前工作目录
command 将指定命令当作外部文件执行而不是函数或内建命令
declare 设置变量的数据类型(同typeset)
dirs 显示目录栈的内容
disable 临时禁用指定的散列表元素
disown 从作业表中移除指定的作业
echo 显示变量和文本
emulate 用zsh来模拟另一个shell,比如Bourne、Korn或C shell
enable 使能指定的散列表元素
eval 在当前shell进程中执行指定的命令和参数
exec 执行指定的命令和参数来替换当前shell进程
exit 退出shell并返回指定的退出状态码。如果没有指定,使用最后一条命令的退出状态码
export 允许在子shell进程中使用指定的环境变量名及其值
false 返回退出状态码1
fc 从历史记录中选择某范围内的命令
fg 以前台模式执行指定的作业
float 将指定变量设为保存浮点值的变量
functions 将指定名称设为函数
getln 从缓冲栈中读取下一个值并将其放到指定变量中
getopts 提取命令行参数中的下一个有效选项并将它放到指定变量中
hash 直接修改命令哈希表的内容
history 列出历史记录文件中的命令
integer 将指定变量设为整数类型
jobs 列出指定作业的信息,或分配给shell进程的所有作业
kill 向指定进程或作业发送信号(默认为SIGTERM)
let 执行算术运算并将结果赋给一个变量
limit 设置或显示资源限制
local 为指定变量设置数据属性
log 显示受watch参数①影响的当前登录到系统上的所有用户
logout 同exit,但只在shell是登录shell时有效
popd 从目录栈中删除下一项
print 显示变量和文本
printf 用C风格的格式字符串来显示变量和文本
pushd 改变当前工作目录,并将上一个目录放到目录栈中
pushln 将指定参数放到编辑缓冲栈中
pwd 显示当前工作目录的完整路径名
read 读取一行,并用IFS变量将数据字段赋给指定变量
readonly 将值赋给不能修改的变量
rehash 重建命令散列表
set 为shell设置选项或位置参数
setopt 为shell设置选项
shift 读取并删除第一个位置参数,然后将剩余的参数向前移动一个位置
source 找到指定文件并将其内容复制到当前位置
suspend 挂起shell的执行,直到它收到SIGCONT信号
test 如果指定条件为TRUE的话,返回退出状态码0
times 显示当前shell以及shell中所有运行进程的累计用户时间和系统时间
trap 阻断指定信号从而让shell无法处理,如果收到信号则执行指定命令true 返回退出状态码0
ttyctl 锁定和解锁显示
type 显示shell会如何解释指定的命令
typeset 设置或显示变量的特性
ulimit 设置或显示shell或shell中运行进程的资源限制
umask 设置或显示创建文件和目录的默认权限
unalias 删除指定的命令别名
unfunction 删除指定的已定义函数
unhash 删除散列表中的指定命令
unlimit 取消指定的资源限制
unset 删除指定的变量特性
unsetopt 删除指定的shell选项
wait 等待指定的作业或进程完成
whence 显示指定命令会如何被shell解释
where 如果shell找到的话,显示指定命令的路径名
which 用csh风格的输出显示指定命令的路径名
zcompile 编辑指定的函数或脚本,加速自动加载
zmodload 对可加载zsh模块执行特定操作

zsh shell在提供内建命令方面太强大了!你可以根据bash中对应的命令来识别出其中的大多数命令。zsh shell内建命令最重要的功能是模块。

  1. 附加模块

有大量的模块可以为zsh shell提供额外的内建命令,而且这个数量还在随着程序员不断增加新模块而不断增长。表23-5列出了在写作本书时比较流行的模块。
表23-5 zsh模块

模块 描 述
zsh/datetime 额外的日期和时间命令及变量
zsh/files 基本的文件处理命令
zsh/mapfile 通过关联数组来访问外部文件
zsh/mathfunc 额外的科学函数
zsh/pcre 扩展的正则表达式库
zsh/net/socket Unix域套接字支持
zsh/stat 访问stat系统调用来提供系统的统计状况
zsh/system 访问各种底层系统功能的接口
zsh/net/tcp 访问TCP套接字
zsh/zftp 专用FTP客户端命令
zsh/zselect 阻塞,直到文件描述符就绪才返回
zsh/zutil 各种shell实用工具

zsh shell模块涵盖了很多方面的功能,从简单的命令行编辑功能到高级网络功能。zsh shell的思想是提供一个基本的、最小化的shell环境,让你在编程时再添加需要的模块。

  1. 查看、添加和删除模块

zmodload命令是zsh模块的管理接口。你可以在zsh shell会话中用这个命令查看、添加或删除模块。
zmodload命令不加任何参数会显示zsh shell中当前已安装的模块。

% zmodload
zsh/zutil
zsh/complete
zsh/main
zsh/terminfo
zsh/zle
zsh/parameter
%

不同的zsh shell实现在默认情况下包含了不同的模块。要添加新模块,只需在zmodload命令行上指定模块名称就行了。

% zmodload zsh/zftp
%

不会有信息表明模块已经加载成功了。你可以再运行一下zmodload命令,新添加的模块会出现在已安装模块的列表中。
23
一旦加载了模块,该模块中的命令就成为了可用的内建命令。

% zftp open myhost.com rich testing1
Welcome to the myhost FTP server.
% zftp cd test
% zftp dir
01-21-11 11:21PM 120823 test1
01-21-11 11:23PM 118432 test2
% zftp get test1 > test1.txt
% zftp close
%

zftp命令允许你直接在zsh shell命令行操作完整的FTP会话!你可以在zsh shell脚本中使用这些命令,直接在脚本中进行文件传输。
要删除已安装的模块,用-u参数和模块名。

% zmodload -u zsh/zftp
% zftp
zsh: command not found: zftp
%

说明 通常习惯将zmodload命令放进$HOME/.zshrc启动文件中,这样在zsh启动时常用的函数就会自动加载。

23.6 zsh 脚本编程

zsh shell的主要目的是为shell程序员提供一个高级编程环境。认识到这点,你就能理解为什么zsh shell会提供那么多方便脚本编程的功能。

23.6.1 数学运算

如你所料,zsh shell可以让你轻松执行数学函数。一直以来,Korn shell因支持使用浮点数而在数学运算支持方面处于领先地位。zsh shell在所有数学运算中都提供了对浮点数的全面支持。

  1. 执行计算

zsh shell提供了执行数学运算的两种方法:

  • let命令
  • 双圆括号

在使用let命令时,你应该在算式前后加上双引号,这样才能使用空格。

% let value1=" 4 * 5.1 / 3.2 "
% echo $value1
6.3750000000
%

注意,使用浮点数会带来精度问题。为了解决这个问题,通常要使用printf命令,并指定能正确显示结果所需的小数点精度。

% printf "%6.3f\n" $value1
6.375
%

现在好多了!
第二种方法是使用双圆括号。这个方法结合了两种定义数学运算的方法。

% value1=$(( 4 * 5.1 ))
% (( value2 = 4 * 5.1 ))
% printf "%6.3f\n" $value1 $value2
20.400
20.400
%

注意,你可以将双圆括号放在算式两边(前面加个美元符)或整个赋值表达式两边。两种方法输出同样的结果。
如果一开始没用typeset命令来声明变量的数据类型,那么zsh shell会尝试自动分配数据类型。这在处理整数和浮点数时很危险。看看下面这个例子。

% value1=10
% value2=$(( $value1 / 3 ))
% echo $value2
3
%

现在这个结果可能并不是你所期望的。在指定数字时没指定小数点后的位数的话,zsh shell会将它们都当成整数值并进行整数运算。要保证结果是浮点数,你必须指定该数小数点后的位数。

% value1=10.
% value2=$(( $value1 / 3. ))
% echo $value2
3.3333333333333335
%

结果是浮点数形式了。

  1. 数学函数

在zsh shell中,内建数学函数可多可少。默认的zsh并不含有任何特殊的数学函数。但如果安装了zsh/mathfunc模块,你就会拥有远远超出你可能需要的数学函数。

% value1=$(( sqrt(9) ))
zsh: unknown function: sqrt
% zmodload zsh/mathfunc
% value1=$(( sqrt(9) ))
% echo $value1
3.
%

非常简单!现在你拥有了一个完整的数学函数库。
23

说明 zsh中支持很多数学函数。要查看zsh/mathfunc模块提供的所有数学函数的清单,可以参看zsh模块的手册页面。

23.6.2 结构化命令

zsh shell为shell脚本提供了常用的结构化命令:

  • if-then-else语句
  • for循环(包括C语言风格的)
  • while循环
  • until循环
  • select语句
  • case语句

zsh中的每个结构化命令采用的语法都跟你熟悉的bash shell中的一样。zsh shell还包含了另外一个叫作repeat的结构化命令。repeat命令使用如下格式。

repeat param
do
commands
done

param参数必须是一个数字或能算出一个数值的数学算式。repeat命令就会执行指定的命令 那么多次。

% cat test1
#!/bin/zsh
# using the repeat command
value1=$(( 10 / 2 ))
repeat $value1
do
  echo "This is a test"
done
$ ./test1
This is a test
This is a test
This is a test
This is a test
This is a test
%

这条命令还允许你基于计算结果执行指定的代码块若干次。

23.6.3 函数

zsh shell支持使用function命令或通用圆括号定义函数名的方式来创建自定义函数。

% function functest1 {
> echo "This is the test1 function"
}
% functest2() {
> echo "This is the test2 function"
}
% functest1
This is the test1 function
% functest2
This is the test2 function
%

跟bash shell函数一样(参见第17章),你可以在shell脚本中定义函数,然后使用全局变量或传递参数给该函数。

23.7 小结

本章讨论了可能遇到的两种流行的可选择Linux shell。dash shell是作为Debian Linux发行版的一部分开发的,主要出现在Ubuntu Linux发行版中。它是Bourne shell的精简版,所以它并不像bash shell一样支持那么多功能,这可能会给脚本编程带来一些问题。
zsh shell通常会用在编程环境中,因为它为shell脚本程序员提供了许多好用的功能。它使用可加载的模块来加载单独的代码库,这使得高级函数的使用与在命令行上运行命令一样简单。从复杂的数学算法到网络应用(如FTP和HTTP),可加载模块支持很多功能。
本书接下来将会深入探讨Linux环境中可能会用到的一些特定脚本编程应用。下一章将介绍如何编写简单的实用工具来协助日常的Linux管理工作。这些工具能够极大简化你的工作。