Shell 技巧 - 特殊变量 II
上个月,我们出人意料地转而专注于 shell 脚本编写和特殊变量表示法的基本知识,而不是解决一些复杂而晦涩的脚本编写难题。本月我将继续我们的讨论,探讨你可以使用变量名引用的内容。作为快速回顾,上个月我们学习了 $0、$、$!、$*、$? 和 $@。
与过去糟糕的编码时代不同,在你的脚本中增加几十个字节不会产生不良影响,也不会占用宝贵的磁盘空间,因此我强烈建议使用更长、便于记忆、描述性的变量名。例如,如果你想用一个变量来帮助你逐步完成循环,不要使用 i,而要使用 loopcount。当你几周或几个月后回头看脚本时,这会让一切都变得容易得多。
如果你已经是一名脚本程序员,你就知道变量是通过使用 $ + 变量名来引用的。因此,让我们坚持使用 account 作为我们的变量名,这样我就可以向你展示一些巧妙的东西。
首先,你已经习惯于将变量引用为 $account,但你也可以使用 ${account},而且通常你必须使用完整形式以确保没有解析错误。
提示: 解析错误?如果你想输出 account 的值,紧接着是数字 001,该怎么办?echo $account001将会失败,因为 shell 会认为你的意思是变量account001,而这个变量不存在。相反,使用 ${} 表示法
echo ${account}001
如果 account 没有定义会发生什么?当它未定义时,echo $account会产生一个空白值。相反,如果能说“如果值已定义,则显示它;否则,显示替代值”就好了。这是这样做的
${account:-alternative value}
请注意,替代值可以嵌入空格——这是 {} 表示法如此受欢迎的另一个原因!
如果想要相同的操作,但也同时将变量设置为指定的值呢?也就是说,用长篇大论来说,脚本片段看起来会像这样
if [ "$account" = "" ] ; then echo "alternative value" account="alternative value" else echo $account fi
但是,有一个非常简短的替代方案:只需引用变量
echo ${account:=alternative value}
如果变量没有值,也许你想生成一条错误消息?只需进行一个微小的符号更改,你就得到了它,天哪
echo ${account:?No account specified}
这个标点符号汤中还有一个:${xx:-yy}表示法显示yy如果$xx未设置或为空,但它不会更改变量本身的值。我在上面几个段落中展示了这一点。但是,如果你想要相反的效果,即如果变量已设置,则显示替代值?你可以使用
${account:+alternative value}
同样,它不会更改变量的实际值。
对于接下来的一组很酷的变量名技巧,让我们跳到一个小的演示脚本
#!/bin/sh account="taylor" echo "account set to ${account:-oops, forgot to set a value}" echo "skip the first two letters: ${account:3}" echo "show me just the third and fifth letter:" \ "${account:3:1} and ${account:5:1}" exit 0
正如你从这个例子中看到的,你可以使用${x:n}表示法从第 n 个字母到结尾访问变量的值。要获得特定长度的切片,请添加第三个变量,${x:n:m},这意味着“显示我从变量 x 的第 n 个字母开始的 m 个字母。”
当我运行上面的脚本时,我看到的是这样的
$ sh test.sh account set to taylor skip the first two letters: lor show me just the third and fifth letter: l and r
简洁明了!
现在,假设你有一个复杂的脚本,它创建了一系列格式为 $account1、$account2、$account3 等的变量。有没有一种方法可以一次访问所有变量名?当然有!让我们设置一些变量
account="taylor" account2="smith" account3="jones" account4="harry"
现在,这是你如何访问它们所有名称的方法
${!account*}
它看起来像这样
echo "variables starting with 'account': ${!account*}"
并且,运行时
variables starting with 'account': account account2 account3 account4
要访问它们的值,你只需在循环中执行此扩展
for varname in ${!account*} do echo \$varname = ${!varname} done
实际上,这是一个棘手的情况,因为你默认可能考虑的所有符号约定(如 $$varname 或 ${$varname})都会失败。相反,${!varname} 执行额外的解引用步骤并获得我们想要的结果
$account = taylor $account2 = smith $account3 = jones $account4 = harry
我将在这里停止,但下个月我们将进一步深入 shell 变量扩展的神秘世界,并讨论内置的文本替换。
Dave Taylor 是一位拥有 26 年 UNIX 经验的资深人士,《Elm Mail System》的创建者,也是畅销书 Wicked Cool Shell Scripts 和 Teach Yourself Unix in 24 Hours 的作者(在他出版的 16 本技术书籍中)。他的主要网站是 www.intuitive.com,他还通过 AskDaveTaylor.com 提供技术支持。你也可以通过 twitter.com/DaveTaylor 在 Twitter 上关注 Dave。