考虑旧版 UNIX/Linux 问题
哎呀,真令人沮丧!十年前,我写了一本相当受欢迎的书,名为《Wicked Cool Shell Scripts》,而我正在撰写新版——十周年纪念版。其中有很多新脚本、全新的章节和旧内容的更新。幸运的是,Bash 在过去十年中并没有发生太大变化,所以几乎所有内容仍然可以正常工作(尽管我现在意识到有些脚本无法处理文件名中的空格——这是我多年前在这个专栏中谈到的)。
但是,当我将以下脚本推送给我的 Google Plus 关注者(在 G+ 上找到我:http://profiles.google.com/d1taylor)并要求那些可以访问 Linux 或 UNIX 系统的人快速运行它时,就出现了问题
#!/bin/sh
# how many commands: count how many executable commands
# are in your current PATH.
myPATH="$(echo $PATH | sed -e 's/ /~~/g' -e 's/:/ /g')"
count=0 ; nonex=0
for dirname in $myPATH ; do
directory="$(echo $dirname | sed 's/~~/ /g')"
if [ -d "$directory" ] ; then
for command in $(ls "$directory") ; do
if [ -x "$directory/$command" ] ; then
count="$(( $count + 1 ))"
else
nonex="$(( $nonex + 1 ))"
fi
done
fi
done
echo "$count commands, and $nonex entries that weren't \
marked executable"
exit 0
它真的很简单——我使用 sed
将 $PATH 值拆分为空格分隔的值,然后使用 for 循环逐个遍历它们,计算有多少条目被标记为可执行 (-x
测试)。
当然,您必须考虑到 PATH 中的目录名中可能存在空格(例如 /User Applications/bin),因此我还将空格转换为 ~~,然后在 for 循环的最后时刻将其转换回来。但这并不是什么高深的科学,只是基本的脚本编写。
您可能会问,为什么要测试 PATH 中的目录是否是实际目录 (-d
测试) 呢?因为当人们可以将自己的目录添加到系统 PATH 中时,可能会变得混乱,并且完全有可能存在不是有效目录的条目。所以这实际上只是错误管理。也许添加 else echo "错误:条目 $directory 不是目录?"
会是一个不错的补充。
无论如何,我发布了这个脚本,人们在各种系统上运行它,报告的答案范围从 1,100 到超过 3,000 个 PATH 中的可执行命令(Ubuntu 13.10)。超过 3,000 个命令?哇!除了我的朋友 Chris 说:
Sun OS 5.8 “for command...” 这行代码给了我这个错误“syntax error at line 10: '$' unexpected”。
这是脚本中的这一行
for dirname in $myPATH ; do
嗯,这很令人费解,因为该语句中没有什么特别复杂的。也许是行中间的 ; 吗?尽管如此,来自 shell 的经典——无用的——错误消息。一番挖掘后,结果证明他有一个不同的默认登录 shell,并且该版本中的 /bin/sh 显然没有链接到 /bin/bash。糟糕。我们更改了第一行以调用正确的 shell
#!/bin/bash
而且……它仍然无法工作
脚本运行了,但它返回了:“First RE may not be null”。第二行显示:“0 commands, and 0 entries that weren't marked executable”。我的路径中有很多可执行文件。
哎呀。现在怎么办?
运行 Solaris 测试脚本合乎逻辑的解决方案是访问运行 Solaris 的系统(理想情况下是 SunOS 5.8,又名 Solaris 8),但是谁会运行 Solaris 系统并可以授予我外部 SSH 访问权限呢?答案是:我找不到任何人,这就是为什么我找到了一个更好的途径:VirtualBox,真是幸运。
VirtualBox 可以从 Oracle 免费下载,VirtualBox 是一种虚拟化系统,可以在系统内部创建系统。更棒的是,它可以在 Mac 或 Windows 系统以及各种 Linux 版本上运行,能够安装和运行完整的 Solaris 安装(或您感兴趣的任何其他操作系统)作为应用程序。
如果您尝试过 VMware 或 Parallels,您已经接触过这项技术,它非常巧妙。实际上,我在我的 MacBook Pro 上使用 VMware Fusion 运行 Windows 8 Pro,它在自己的全屏窗口中运行得非常好。缺点是 VMware Fusion 不是免费的。但是,VirtualBox 是免费的——太好了。
下载并安装它,然后您可以从 http://www.oracle.com/technetwork/server-storage/solaris11/vmtemplates-vmvirtualbox-1949721.html 获取 SunOS 5.11(又名 Solaris 11.1)的免费副本。
解压操作系统并双击。它会自动被 VirtualBox 打开,再点击一两次,您就可以运行 Solaris 11.1 并拥有默认的窗口管理器 GNOME,位于最前面和中心位置,如图 1 所示。

图 1. 在 Mac OS X 的 VirtualBox 中运行的 Solaris 11.1
现在终于,我可以打开一个 xterm 并在 Solaris 环境中测试脚本了。最简单的途径是什么?调整 VirtualBox 配置以与父操作系统共享剪贴板,您可以简单地将其复制并粘贴到 vi 编辑缓冲区中并保存它。
一个调用
$ sh ./count-cmds.sh
2003 commands, and 15 entries that weren't marked executable
啊,太好了。因此,实际上,该脚本在最新版本的 SunOS/Solaris 中可以正常工作,但在 Chris 运行的旧版本中却失败了。它有多旧?事实证明,Solaris 8 是在很久以前发布的,在 2004 年 2 月。与我的书出版的同一年,我在出版前在 Solaris 9 上测试了脚本。
这引出了一个难题:该脚本显然在十年前的 Solaris UNIX 版本中无法工作,但在最新版本 Solaris 11 中却可以正常工作。我应该在意吗?
这一切都与遗留问题有关:您需要追溯到多久以前才能确保您的软件能够工作?之前的操作系统版本?五年前?十年前?更久?遗留支持一直是 Windows 用户新闻的焦点,这是肯定的,因为微软刚刚取消了对旗舰操作系统旧版本 Windows XP 的支持。记录在案,WinXP 于 2001 年 10 月发布。十四年后,微软表示“伙计们,从那以后我们已经发布了很多主要版本,不能永远支持它”,人们都在抱怨。
苹果似乎更优雅地应对了这类事情。当公司从 MacOS 迁移到 Mac OS X 时,它包含了“经典模式”,旧应用程序在其中大部分可以运行,但从 OS X 时代开始,苹果公司不打算“像微软那样”多年支持旧操作系统,这一点已经写在墙上了。
而且,这让我回到了 Solaris 8 和《Wicked Cool Shell Scripts》。长话短说:如果脚本在 Solaris 11 中无法正常工作,我会担心并调试问题,但因为它在十年前的操作系统版本中失败了,我将忽略这个问题。如果我可以登录到 Solaris 8 系统,我可能会无论如何都调试它,只是为了了解发生了什么,但这是否是减慢本书修订速度的理由?我不这么认为。
遗留支持——对于每个软件开发人员来说,这都是一个巨大的挑战,尽管 Bash 和 Linux 命令行世界在过去几年中变化不大,但在发布您自己的软件(即使它是免费软件)之前,仍然需要考虑这一点。
那么您的解决方案是什么?请写信给我们,让我们知道您的公司如何处理遗留的 Linux/UNIX 问题!