运行shell脚本中的单个命令自然有用,但这有其自身的限制。通常你会需要在shell命令使用
其他数据来处理信息。这可以通过变量来实现。变量允许你临时性地将信息存储在shell脚本中,
以便和脚本中的其他命令一起使用。本节将介绍如何在shell脚本中使用变量。
11.4.1 环境变量
你已经看到过Linux的一种变量在实际中的应用。第6章介绍了Linux系统的环境变量。也可
以在脚本中访问这些值。
shell维护着一组环境变量,用来记录特定的系统信息。比如系统的名称、登录到系统上的用
户名、用户的系统ID(也称为UID)、用户的默认主目录以及shell查找程序的搜索路径。可以用
set命令来显示一份完整的当前环境变量列表。
$ set
BASH=/bin/bash
[…]
HOME=/home/Samantha
HOSTNAME=localhost.localdomain
HOSTTYPE=i386
IFS=$’ \t\n’
IMSETTINGS_INTEGRATE_DESKTOP=yes
IMSETTINGS_MODULE=none
LANG=en_US.utf8
LESSOPEN=’|/usr/bin/lesspipe.sh %s’
LINES=24
LOGNAME=Samantha
[…]
在脚本中,你可以在环境变量名称之前加上美元符($)来使用这些环境变量。下面的脚本
演示了这种用法。
$ cat test2
!/bin/bash
display user information from the system.
echo “User info for userid: $USER”
echo UID: $UID
echo HOME: $HOME
$
$USER、$UID和$HOME环境变量用来显示已登录用户的有关信息。脚本输出如下:
$chmod u+x test2 $ ./test2
User info for userid: Samantha
UID: 1001
HOME: /home/Samantha
$
注意,echo命令中的环境变量会在脚本运行时替换成当前值。另外,在第一个字符串中可
以将$USER系统变量放置到双引号中,而shell依然能够知道我们的意图。但采用这种方法也有一
个问题。看看下面这个例子会怎么样。
$ echo “The cost of the item is $15”
The cost of the item is 5
显然这不是我们想要的。只要脚本在引号中出现美元符,它就会以为你在引用一个变量。在
这个例子中,脚本会尝试显示变量$1(但并未定义),再显示数字5。要显示美元符,你必须在它
前面放置一个反斜线。
$ echo “The cost of the item is \$15”
The cost of the item is $15
看起来好多了。反斜线允许shell脚本将美元符解读为实际的美元符,而不是变量。下一节将
会介绍如何在脚本中创建自己的变量。
说明 你可能还见过通过${variable}形式引用的变量。变量名两侧额外的花括号通常用来帮
助识别美元符后的变量名。
11.4.2 用户变量
除了环境变量,shell脚本还允许在脚本中定义和使用自己的变量。定义变量允许临时存储数
据并在整个脚本中使用,从而使shell脚本看起来更像一个真正的计算机程序。
用户变量可以是任何由字母、数字或下划线组成的文本字符串,长度不超过20个。用户变量
区分大小写,所以变量Var1和变量var1是不同的。这个小规矩经常让脚本编程初学者感到头疼。
使用等号将值赋给用户变量。在变量、等号和值之间不能出现空格(另一个困扰初学者的用
法)。这里有一些给用户变量赋值的例子。
var1=10
var2=-57
var3=testing
var4=”still more testing”
shell脚本会自动决定变量值的数据类型。在脚本的整个生命周期里,shell脚本中定义的变量
会一直保持着它们的值,但在shell脚本结束时会被删除掉。
与系统变量类似,用户变量可通过美元符引用。
$ cat test3
!/bin/bash
testing variables
days=10
guest=”Katie”
echo “$guest checked in $days days ago”
days=5
guest=”Jessica”
echo “$guest checked in $days days ago”
$
运行脚本会有如下输出。 $ chmod u+x test3
$ ./test3
Katie checked in 10 days ago
Jessica checked in 5 days ago
$
变量每次被引用时,都会输出当前赋给它的值。重要的是要记住,引用一个变量值时需要使
用美元符,而引用变量来对其进行赋值时则不要使用美元符。通过一个例子你就能明白我的意思。
$ cat test4
#!/bin/bash
# assigning a variable value to another variable
value1=10
value2=$value1
echo The resulting value is $value2
$
在赋值语句中使用value1变量的值时,仍然必须用美元符。这段代码产生如下输出。
$ chmod u+x test4
$ ./test4
The resulting value is 10
$
要是忘了用美元符,使得value2的赋值行变成了这样:
value2=value1
那你会得到如下输出:
$ ./test4
The resulting value is value1
$
没有美元符,shell会将变量名解释成普通的文本字符串,通常这并不是你想要的结果。
11.4.3 命令替换
shell脚本中最有用的特性之一就是可以从命令输出中提取信息,并将其赋给变量。把输出赋
给变量之后,就可以随意在脚本中使用了。这个特性在处理脚本数据时尤为方便。
有两种方法可以将命令输出赋给变量:
反引号字符(`)
$()格式
要注意反引号字符,这可不是用于字符串的那个普通的单引号字符。由于在shell脚本之外很
少用到,你可能甚至都不知道在键盘什么地方能找到这个字符。但你必须慢慢熟悉它,因为这是
许多shell脚本中的重要组件。提示:在美式键盘上,它通常和波浪线(~)位于同一键位。
命令替换允许你将shell命令的输出赋给变量。尽管这看起来并不那么重要,但它却是脚本编
程中的一个主要组成部分。
要么用一对反引号把整个命令行命令围起来:
testing=’date’
要么使用$()格式:
testing=$(date)
shell会运行命令替换符号中的命令,并将其输出赋给变量testing。注意,赋值等号和命令
替换字符之间没有空格。这里有个使用普通的shell命令输出创建变量的例子。
$ cat test5
#!/bin/bash
testing=$(date)
echo “The date and time are: “ $testing
$
变量testing获得了date命令的输出,然后使用echo语句显示出它的值。运行这个shell脚
本生成如下输出。
$ chmod u+x test5
$ ./test5
The date and time are: Mon Jan 31 20:23:25 EDT 2014
$
这个例子毫无吸引人的地方(也可以干脆将该命令放在echo语句中),但只要将命令的输出
放到了变量里,你就可以想干什么就干什么了。
下面这个例子很常见,它在脚本中通过命令替换获得当前日期并用它来生成唯一文件名。
#!/bin/bash
# copy the /usr/bin directory listing to a log file
today=$(date +%y%m%d)
ls /usr/bin -al > log.$today
today变量是被赋予格式化后的date命令的输出。这是提取日期信息来生成日志文件名常用
的一种技术。+%y%m%d格式告诉date命令将日期显示为两位数的年月日的组合。
$ date +%y%m%d
140131
$
这个脚本将日期值赋给一个变量,之后再将其作为文件名的一部分。文件自身含有目录列表
的重定向输出(将在11.5节详细讨论)。运行该脚本之后,应该能在目录中看到一个新文件。
-rw-r—r— 1 user user 769 Jan 31 10:15 log.140131
目录中出现的日志文件采用$today变量的值作为文件名的一部分。日志文件的内容是
/usr/bin目录内容的列表输出。如果脚本在明天运行,日志文件名会是log.140201,就这样为新的
一天创建一个新文件。
警告 命令替换会创建一个子shell来运行对应的命令。子shell(subshell)是由运行该脚本的shell
所创建出来的一个独立的子shell(child shell)。正因如此,由该子shell所执行命令是无法
使用脚本中所创建的变量的。
在命令行提示符下使用路径./运行命令的话,也会创建出子shell;要是运行命令的时候
不加入路径,就不会创建子shell。如果你使用的是内建的shell命令,并不会涉及子shell。
在命令行提示符下运行脚本时一定要留心!