13.10.1 变量类型
变量可分为两类:局部变量和环境变量。局部变量只在创建它们的shell 中可用。而环境变量则可以在创建它们的shell 及其派生出来的任意子进程中使用。有些变量是用户创建的,其他的则是专用shell 变量。
13.10.2 命名惯例
变量名必须以字母或下划线字符开头。其余的字符可以是字母、数字(0~9) 或下划线字符。任何其他的字符都标志着变量名的终止。名字是大小写敏感的。给变量赋值时,等号周围不能有任何空白符。为了给变量赋空值,可以在等号后跟一个换行符。创建一个局部变量最简单的格式是给一个变量赋值,如以下格式所示。
格式
变量= 值
范例 13-49
name=Tommy
13.10.3 内置命令 declare
有两个内置命令可以用来创建变量,它们是declare 和typeset ,其选项可以控制变量设置的方式。typeset 命令( 来自Korn shell) 的功能和declare 命令(bash) 完全一样。bash 文档中指出,“ 提供typeset 命令是为了和Korn shell 兼容。但是不建议使用它,而应使用内置命令declare” 12 。因此从这一点来说,我们将使用declare 命令( 即使我们使用typeset 也一样方便) 。
不带任何参数时,declare 将列出所有已设置的变量。通常只读变量不能被重新赋值或复位。如果只读变量是用declare 创建的,那它们不可以被复位,但可以被重新赋值。整型变量也可以用declare 赋值。
格式
declare 变量= 值
范例13-50
declare name=Tommy
表 13-13 declare 选项
选 项 |
含 义 |
-a 13 |
将变量当作一个数组。即,分配元素 |
-f |
列出函数的名称和定义 |
-F |
只列出函数名 |
-i |
将变量设为整型 |
-r |
将变量设为只读 |
-x |
将变量名输出到子 shell 中 |
13.10.4 局部变量和作用域
变量的作用域指变量在一个程序中的哪些地方可见。对于shell 来说,局部变量的作用域被限定在创建它们的shell 中。
给变量赋值时,等号前后不能有空白符。如果要给变量赋空值,可以在等号后跟一个换行符 。14
变量前的美元符用来提取存储在变量里的值。
local 函数可以用来创建局部变量,但仅限于在函数内使用 ( 请参见 13.16.1 节, “ 定义函数 ”) 。
设置局部变量 局部变量可以通过简单地赋予它一个值或一个变量名来设置,或者如范例13-51 所示用declare 内置函数来设置。
范例13-51
1 $ round=world or declare round=world
$ echo $round
world
2 $ name="Peter Piper"
$ echo $name
Peter Piper
3 $ x=
$ echo $x
4 $ file.bak="$HOME/junk"
bash: file.bak=/home/jody/ellie/junk: not found
说明
1. 将局部变量 round 赋值为 world 。如果遇到变量名前面是个美元符的情况, shell 就执行变量替换。该命令显示变量 round 的值 ( 不要混淆提示符 ($) 和用来执行变量替换的 $ 符 ) 。
2. 局部变量 name 被赋值为 “Peter Piper” 。必须用引号来保护空白符,这样, shell 分析命令行时才不会将这个字符串看成是两个词。该命令显示变量 name 的值。
3. 这条命令没有给变量 x 赋值,因此 x 被赋值为空。结果显示一个空值,即空字符串。
4. 变量名中出现句点是非法的。变量名可以使用的字符只能是数字、字母和下划线。因此, shell 尝试将这个字符串作为一条命令来执行。
范例 13-52
1 $ echo $$
1313
2 $ round=world
$ echo $round
world
3 $ bash # Start a subshell
4 $ echo $$
1326
5 $ echo $round
6 $ exit # Exits this shell, returns to parent shell
7 $ echo $$
1313
8 $ echo $round
world
说明
1. 双美元符变量的值是当前 shell 的 PID 。本例中这个 shell 的 PID 是 1313 。
2. 将局部变量 round 赋值为字符串 world ,并打印该变量的值。
3. 另外启动一个 bash shell ,这个 shell 被称为子 shell(subshell 或 child shell) 。
4. 当前这个 shell 的 PID 时 1326 ,其父 shell 的 PID 则是 1313 。
5. 局部变量 round 在这个 shell 中没有定义,因此打印了一个空行。
6. exit 命令终止当前 shell 并返回父 shell( 也可以按 Ctrl+D 组合键退出当前 shell) 。
7. 返回到父 shell 。显示它的 PID 。
8. 显示变量 round 的值。它是这个 shell 的局部变量。
设置只读变量 只读变量是不能被重新定义或复位的特殊变量。但是,如果使用了declare 函数,只读变量可以被重新定义,但不能被复位。
范例13-53
1 $ name=Tom
2 $ readonly name
$ echo $name
Tom
3 $ unset name
bash: unset: name: cannot unset: readonly variable
4 $ name=Joe
bash: name: readonly variable
5 $ declare -r city='Santa Clara'
6 $ unset city
bash: unset: city: cannot unset: readonly variable
7 $ declare city='San Francisco' # What happened here?
$ echo $city
San Francisco
说明
1. 局部变量 name 的值被设为 Tom 。
2. 将变量 name 设为只读。
3. 不能复位只读变量。
4. 不能重新定义只读变量。
5. declare 内置命令给只读变量 city 赋值 Santa Clara 。当所赋值串中包含空白符时必须用引号。
6. 因其是只读变量,所以不能被复位。
7. 当只读变量是由 declare 命令创建时,它不可以被复位,但可以被重新赋值。
13.10.5 环境变量
环境变量可用在创建它们的shell 和从该shell 派生的任意子shell 或进程中。它们通常被称为全局变量,以区别于局部变量。通常,环境变量应该大写。环境变量是已经用export 内置命令导出的变量。
变量被创建时所处的shell 被称为父shell 。如果父shell 又启动了一个shell ,这个新的shell 被称作子shell 。环境变量将传递给从创建它们的shell 里启动的任意子进程。它们从父亲传递给儿子再到孙子等,但是不可向其他方向传递。比如,一个子进程可以创建环境变量,但不能将它传回给它的父进程,只能传给它的子进程 15 。有一些环境变量,比如HOME 、LOGNAME 、PATH 和SHELL ,在用户登录之前就已经被/bin/login 程序设置好了。通常,环境变量定义并保存在用户主目录下的.bash_profile 文件中。请参见表13-14 中列出的环境变量。
表 13-14 bash 环境变量
变 量 名 |
含 义 |
_( 下划线 ) |
上一条命令的最后一个参数 |
BASH |
展开为调用 bash 实例时使用的全路径名 |
BASH_ENV |
和 ENV 一样,但只可在 bash 2.0 或更高版本中设置 16 |
BASH_VERSINFO |
使用 2.0 以上版本的 bash 时,展开为版本信息 16 |
BASH_VERSION |
展开为当前 bash 实例的版本号 |
CDPATH |
cd 命令的搜索路径。它是以冒号分隔的目录列表, shell 通过它来搜索 cd 命令指定的目标目录。例如 .:~:/usr |
COLUMNS |
设置该变量就给 shell 编辑模式和选择的命令定义了编辑窗口的宽度 |
DIRSTACK |
在 2.0 或以上版本的 bash 中,代表目录栈的当前内容 |
EDITOR |
内置编辑器 emacs 、 gmacs 或 vi 的路径名 |
ENV |
每一个新的 bash shell( 包括脚本 ) 启动时执行的环境文件。通常赋予这个变量的文件名是 .bashrc 。 ENV 的值被解释为路径名前, shell 先要对其进行参量扩展,命令替换和算术扩展 |
EUID |
展开为在 shell 启动时被初始化的当前用户的有效 ID |
FCEDIT |
fc 命令的默认编辑器名 |
FIGNORE |
执行文件名补全时可忽略的以冒号分隔的后缀列表。以 FIGNORE 中任一项为后缀的文件名被从匹配的文件名列表中排除。例如值为 .o:~ |
FORMAT |
用来格式化在命令管道上的 time 关键字的输出 |
GLOBIGNORE |
在文件名扩展 ( 称为 globbing) 时被忽略的文件列表 |
GROUPS |
当前用户所属的组 |
HISTCMD |
当前命令的历史编号或在历史清单中的序号。如果 HISTCMD 被复位,即使它随后就会重置,也将失去它的特殊属性 |
HISTCONTROL |
如果设置了 ignorespace 值,以一个空格符开头的行将不会进入历史清单。如果设置了 ignoredups 值,那和前一个历史行匹配的行不会进入。值 ignoreboth 结合了这两个选项。如果被复位,或设置成除了上面所说的任意其他值时,所有被解释器所读的行都将保存到历史清单中 |
HISTFILE |
指定保存命令行历史的文件。默认值是 ~/.bash_history 。如果被复位,交互式 shell 退出时将不保存命令行历史 |
( 续表 )
变 量 名 |
含 义 |
HISTFILESIZE |
历史文件能包含的最大行数。当给这个变量赋值后,如果有必要,历史文件将被截尾,以使包含的行数不超过这个数。默认值是 500 |
HISTSIZE |
记录在命令行历史文件中的命令数。默认是 500 |
HOME |
主目录。未指定目录时, cd 命令将转向该目录 |
HOSTFILE |
包含一个格式和 /etc/hosts 一样的文件的名称,当 shell 需要补全一个主机名时将读取该文件。文件可以交互式更改。下一次试图补全主机名时, bash 将新文件的内容添加到已经存在的数据库中 |
HOSTTYPE |
自动设置正在运行 bash 的机器的类型。默认值是由系统决定的 |
IFS |
内部字段分隔符,一般是空格符、制表符和换行符,用于由命令替换,循环结构中的表和读取的输入产生的词的字段划分 |
IGNOREEOF |
控制 shell 接收到单独一个 EOF 字符作为输入时的行为。如果设置,它的值就是 shell 退出前在一个输入行的最前面键入的连续 EOF 字符的个数。如果变量存在但没有一个数字值,或没有值,那么默认值是 10 。如果它不存在, EOF 意味着给 shell 的输入的终止。它只在交互式 shell 中有效 |
INPUTRC |
readline 启动文件的文件名,取代默认的 ~/.inputrc |
LANG |
用来为没有以 LC_ 开头的变量明确选取的种类确定 locale 类 |
LC_ALL |
忽略 LANG 和任何其他 LC_ 变量的值 |
LC_COLLATE |
确定对路径名扩展的结果进行排序时的整理顺序,以及匹配文件名与模式时的范围表达式,等价类和整理序列的行为 |
LC_MESSAGES |
确定用于转换前面有一个 $ 的双引号串的 locale |
LINENO |
每次 shell 在一个脚本或函数中替换代表当前连续行号 ( 从 1 开始 ) 的十进制数时,都将引用该参数 |
MACHTYPE |
包含一个描述正在运行 bash 的系统的串 |
|
如果该参数被设置为某个邮件文件的名称,而 MAILPATH 未被设置,当邮件到达 MAIL 指定的文件时, shell 会通知用户 |
MAIL_WARNING |
如果设置了该变量,当 bash 发现用于检查邮件的文件在上次检查后又被访问了,将打印消息 “The mail in [filename where mail is stored] has been read” |
MAILCHECK |
这个参数定义 shell 将隔多长时间 ( 以秒为单位 ) 检查一次由参数 MAILPATH 或 MAILFILE 指定的文件,看看是否有邮件到达。默认值是 600 秒 (10 分钟 ) 。如果将它设为 0 , shell 每次输出主提示符之前都会去检查邮件 |
MAILPATH |
由冒号分隔的文件名列表。如果设置了这个参数,只要有邮件到达任何一个由它指定的文件, shell 都会通知用户。每个文件名后面都可以跟一个百分号和一条消息,当文件修改时间发生变化时, shell 会显示这条消息。默认的消息是: You have mail |
( 续表 )
变 量 名 |
含 义 |
OLDPWD |
前一个工作目录 |
OPTARG |
上一个由 getopts 内置命令处理的选项参数的值 |
OPTERR |
如果设置成 1 ,显示来自 getopts 内置命令的错误信息 |
OPTIND |
下一个由 getopts 内置命令处理的参数的序号 |
OSTYPE |
自动设置成一个串,该串描述正在运行 bash 的操作系统。默认值由系统决定 |
PATH |
命令搜索路径。一个由冒号分隔的目录列表, shell 用它来搜索命令。默认路径由系统决定,并且由安装 bash 的管理员设置。一个普通值为 /usr/gnu/bin:/usr/local/bin:/usr/ucb:/usr/bin: |
PIPESTATUS |
一个数组,包含一列最近在管道执行的前台作业的进程退出状态值 |
PPID |
父进程的进程 ID |
PROMPT_COMMAND |
赋给这个变量的命令将在主提示符显示前执行 |
PS1 |
主提示符串,默认值是 $ |
PS2 |
次提示符串,默认值是 > |
PS3 |
与 select 命令一起使用的选择提示符串,默认值是 #? |
PS4 |
当开启追踪时使用的调试提示符串,默认值是 + 。追踪可以用 set –x 开启 |
PWD |
当前工作目录。由 cd 设置 |
RANDOM |
每次引用该变量,就产生一个随机整数。随机数序列可以通过给 RANDOM 赋值来初始化。如果 RANDOM 被复位,即使随后再设置,它也将失去特定的属性 |
REPLY |
当没有给 read 提供参数时设置 |
SECONDS |
每次 SECONDS 被引用,将返回调用 shell 以来的秒数。如果给 SECONDS 赋一个值,以后引用返回的值将是赋值以来的秒数加上所赋的值。如果 SECONDS 被复位,即使随后再设置,它也将失去特定的属性 |
SHELL |
当调用 shell 时,它扫描环境变量以寻找该名字。 shell 给 PATH 、 PS1 、 PS2 、 MAILCHECK 和 IFS 设置默认值。 HOME 和 MAIL 由 login(1) 设置 |
SHELLOPTS |
包含一列开启的 shell 选项,比如 braceexpand 、 hashall 、 monitor 等 |
SHLVL |
每启动一个 bash 实例时将其加 1 |
TMOUT |
设置退出前等待输入的秒数 |
UID |
展开为当前用户的用户 ID ,在 shell 启动时初始化 |
设置环境变量 如果想设置环境变量,就要在给变量赋值之后或设置变量时使用export 命令( 参见表13-15) 。带-x 选项的declare 内置命令也可完成同样的功能( 输出变量时不要在变量名前面加$) 。
表 13-15 export 命令和它的选项
选 项 |
值 |
-- |
标志着选项末尾,余下的参数被视为变量 |
-f |
名 - 值对被看作函数,而不是变量 |
-n |
将一个全局 ( 导出 ) 变量转换成局部变量。之后该变量将不能被导出到子进程中 |
-p |
显示所有的全局变量 |
格式
export 变量 = 值
变量 = 值; export 变量
declare –x 变量 = 值
范例 13-54
export NAME=john
PS1= '/d:/W:$USER> ' ; export PS1
declare -x TERM=sun
范例13-55
1 $ export TERM=sun # or declare -x TERM=sun
2 $ NAME="John Smith"
$ export NAME
$ echo $NAME
John Smith
3 $ echo $$
319 # pid number for parent shell
4 $ bash # Start a subshell
5 $ echo $$
340 # pid number for new shell
6 $ echo $NAME
John Smith
7 $ declare -x NAME="April Jenner"
$ echo $NAME
April Jenner
8 $ exit # Exit the subshell and go back to parent shell
9 $ echo $$
319 # pid number for parent shell
10 $ echo $NAME
John Smith
说明
1. 给 TERM 变量赋值 sun 。同时输出它。现在,由这个 shell 启动的所有进程都将继承这个变量。也可以用 declare –x 来完成同样的功能。
2. 定义并输出变量 NAME ,让它可以被当前 shell 启动的所有子 shell 使用。
3. 打印当前 shell 的 PID 的值。
4. 启动一个新的 bash 。这个新 shell 称为子 shell 。原来那个 shell 称为父 shell 。
5. 新的 bash shell 的 PID 保存在变量 $$ 中,回显这个变量的值。
6. 在父 shell 中设置的变量 NAME 导出给这个新 shell ,这条命令显示它的值。
7. 内置的 declare 函数是设置变量的另一种方式。用 -x 开关, declare 可以输出变量。该变量被重新设置为 April Jenner 。这个变化将输出到所有的子 shell ,但不会影响父 shell 。输出的变量不会向上传递给父 shell 。
8. 退出这个 bash 子 shell 。
9. 再次显示父 shell 的 PID 。
10. 变量NANE 的值还跟原来一样。从父shell 输出到子shell 时,变量保持它们的值不变。子shell 不可能改变父shell 的变量的值。
13.10.6 复位变量
只要不被设为只读,局部变量和环境变量都可以用unset 命令复位。
范例13-56
unset name; unset TERM
说明
unset 命令从 shell 存储器中删除变量。
13.10.7 显示变量值
echo 命令 内置echo 命令将它的参数显示到标准输出上。echo 加-e 选项,允许使用大量控制输出外观的转义序列。表13-16 列出了echo 选项和转义序列。
表 13-16 echo 选项和转义序列
选 项 |
含 义 |
-e |
允许解释下面列出的转义序列 |
-E |
禁止解释这些转义字符,即使在那些默认解释它们的系统上 (bash 2.x) 17 |
-n |
删除输出结果中行尾的换行符 |
转义序列 |
|
\a |
报警 ( 铃 ) |
\b |
退格 |
\c |
不带换行符打印一行 |
\f |
换页 |
\n |
换行 |
\r |
回车 |
\t |
制表符 |
\v |
纵向制表符 |
\\ |
反斜杠 |
\nnn |
ASCII 码是 nnn( 八进制 ) 的字符 |
当使用转义序列时,不要忘记用-e 开头。
范例 13-57
1 $ echo The username is $LOGNAME.
The username is ellie.
2 $ echo -e "/t/tHello there/c"
Hello there$
3 $ echo -n "Hello there"
Hello there$
说明
1. echo 命令将它的参数打印到屏幕上。 shell 会在执行 echo 命令之前先进行变量替换。
2. 带 -e 选项的 echo 命令支持转义序列,和 C 编程语言类似。 $ 是 shell 提示符。
3. 当 -n 选项打开时,不带换行符打印一行。这个版本的 echo 不支持转义序列。
printf 命令 printf 18 的GNU 版本可以用来编排打印输出的格式。它以和C printf 函数相同的方式打印格式串。格式由一个串组成,它包含描述打印输出结果的格式指令。格式指令由带格式符(diouxXfeEgGcs) 的% 指定,%f 代表一个浮点数,%d 则代表一个( 十进制) 整数。
要得到printf 格式符的完整清单以及如何使用它们,可以在命令行键入:printf --help 。键入printf --version 就可以知道使用的printf 是什么版本。如果使用的是bash 2.x ,内置printf 命令所用的格式和/usr/bin 下的printf 可执行程序完全一样。
格式
printf 格式[ 参数…]
范例 13-58
printf "%10.2f%5d/n" 10.5 25
表 13-17 printf 命令的格式符
格 式 符 |
值 |
/" |
双引号 |
/0NNN |
一个八进制字符,这里 NNN 代表 0~3 位 |
// |
反斜杠 |
/a |
报警或蜂鸣 |
/b |
退格 |
/c |
不产生更多的输出 |
/f |
换页 |
/n |
换行 |
/r |
回车 |
( 续表 )
格 式 说 明 |
值 |
/t |
水平制表符 |
/v |
垂直制表符 |
/xNNN |
十六进制字符,这里 NNN 是 1~3 位 |
%% |
单个百分号 |
%b |
字符串参数,也对 / 转义字符进行解释 |
范例 13-59
1 $ printf --version
printf (GNU sh-utils) 1.16
2 $ type printf
printf is a shell builtin
3 $ printf "The number is %.2f/n" 100
The number is 100.00
4 $ printf "%-20s%-15s%10.2f/n" "Jody" "Savage" 28
Jody Savage 28.00
5 $ printf "|%-20s|%-15s|%10.2f|/n" "Jody" "Savage" 28
Jody |Savage | 28.00|
6 $ printf "%s's average was %.1f%%./n" "Jody" $(( (80+70+90)/3 ))
Jody's average was 80.0%.
说明
1. 显示 printf 命令的 GNU 版本。
2. 如果使用的是 bash 2.x , printf 是一个内置命令。
3. 按照说明符 %.2f 指定的格式,参数 100 以保留两位小数的浮点数形式输出。与 C 函数不同的是,这里不需要用逗号来分隔参数。
4. 格式串指明将进行 3 个变换:第一个是 %-20s( 一个左对齐,长度为 20 的字符串 ) ,接着是 %-15s( 一个左对齐,长度为 15 的字符串 ) ,最后一个则是 %10.2f( 一个右对齐,长度为 10 的浮点数,其中的一个字符是句点,最后两个字符是小数点右边的两个数 ) 。参数按对应 % 号的顺序被格式化,因此字符串 Jody 对应第一个 % ,字符串 Savage 对应第二个 % ,数字 28 则对应最后一个 % 号。
5. 该行和第 4 行一样,唯一的区别是增加了竖杠以说明串是左对齐还是右对齐的。
6. printf 命令格式化字符串 Jody 和算术扩展的结果 ( 请参见 13.13 节, “ 算术扩展 ”) 。需要两个百分号 (%%) 才能输出一个百分号 (%) 。
13.10.8 变量扩展修饰符
我们可以用一些专用修饰符来测试和修改变量。修饰符首先提供一个简单的条件测试,用来检查某个变量是否已经被设置,然后根据测试结果给变量赋一个值。请参见表13-18 列出的变量修饰符。
表 13-18 变量修饰符
修 饰 符 |
值 |
${variable:-word} |
如果变量 variable 已被设置且非空,则代入它的值。否则,代入 word |
${variable:=word} |
已被设置且值非空,就代入它的值。否则,将 variable 的值设为 word 。始终代入 variable 的值。位置参量不能用这种方式赋值 |
${variable:+word} |
如果变量 variable 已被设置且值非空,代入 word 。否则,什么都不代入 ( 代入空值 ) |
${variable:?word} |
如果变量 variable 已被设置且值非空,就代入它的值。否则,输出 word 并且从 shell 退出。如果省略了 word ,就会显示信息: parameter null or not set |
${variable:offset} |
获得变量 variable 值中位置从 offset 开始的子串,偏移为从 0 到串的末尾 19 |
${variable:offset:length} |
获得变量 variable 值中位置从 offset 开始长度为 length 的子串 |
和冒号配合使用时,修饰符(- 、= 、+ 、?) 检查变量是否尚未赋值或值为空。不加冒号时,值为空的变量也被认为已设置。
范例 13-60
( 临时替换默认值 )
1 $ fruit=peach
2 $ echo ${fruit:–plum}
peach
3 $ echo ${newfruit:–apple}
apple
4 $ echo $newfruit
5 $ echo $EDITOR # More realistic example
6 $ echo ${EDITOR:-/bin/vi}
/bin/vi
7 $ echo $EDITOR
8 $ name=
$ echo ${name-Joe}
9 $ echo ${name:-Joe}
Joe
说明
1. 将变量 fruit 的值设为 peach 。
2. 这个专用修饰符将检查变量 fruit 是否已被设置。如果 fruit 已被设置,就显示它。否则,用 plum 替换 fruit ,并显示该值。
3. 变量 newfruit 未曾被设置。值 apple 将暂时替换 newfruit 。
4. 上一行的设置是暂时的,因此,变量 newfruit 仍未被设置。
5. 环境变量 EDITOR 尚未被设置。
6. 修饰符 :- 将 /bin/vi 替换为 EDITOR 。
7. EDITOR 未曾被设置过,因此什么都不会打印。
8. 变量 name 被设为空值。因为修饰符前面没有冒号,变量即使为空也被认为是设置过的,所以没有把新的值 Joe 赋给变量 name 。
9. 冒号使得修饰符检查变量是否未设置或为空。只要是这两种情况之一,就用值 Joe 替换 name 。
范例 13-61
( 永久替换默认值 )
1 $ name=
2 $ echo ${name:=Peter}
Peter
3 $ echo $name
Peter
4 $ echo ${EDITOR:=/bin/vi}
/bin/vi
5 $ echo $EDITOR
/bin/vi
说明
1. 赋给变量 name 一个空值。
2. 用修饰符 := 将检查变量 name 是否尚未被设置。如果已经被设置过了,就不会被改变。如果尚未设置或值为空,就将等号右边的值赋给它。由于之前已将变量 name 设置为空,所以现在要把 Peter 赋给它。这个设置是持久的。
3. 变量 name 的值还是 Peter 。
4. 把变量 EDITOR 设置为 /bin/vi 。
5. 显示变量 EDITOR 的值。
范例 13-62
( 临时替换值 )
1 $ foo=grapes
2 $ echo ${foo:+pears}
pears
3 $ echo $foo
grapes
$
说明
1. 将变量 foo 的值设置为 grapes 。
2. 专用修饰符 := 将检查变量 name 是否已被设置。如果已经被设置过,就用 pears 暂时替换 foo 。否则,返回空。
3. 变量 foo 的值还是原来的值。
范例 13-63
( 基于默认值创建错误信息 )
1 $ echo ${namex:?"namex is undefined"}
namex: namex is undefined
2 $ echo ${y?}
y: parameter null or not set
说明
1. 修饰赋 :? 检查变量是否已被设置。如果尚未设置该变量,就把问号右边的信息打印在标准错误输出上。如果此时是在执行脚本,就退出脚本。
2. 如果问号后面没有提供报错信息, shell 就向标准错误输出发送默认的消息。
范例 13-64
( 创建子串 20 )
1 $ var=notebook
2 $ echo ${var:0:4}
note
3 $ echo ${var:4:4}
book
4 $ echo ${var:0:2}
no
说明
1. 给变量赋值 notebook 。
2. var 的子串从偏移 0(notebook 中的 n) 开始,长度为 4 个字符,在 e 处结束。
3. var 的子串从偏移 4(notebook 中的 b) 开始,长度为 4 个字符,在 k 处结束。
4. var 的子串从偏移 0(notebook 中的 n) 开始,长度为 2 个字符,在 o 处结束。
13.10.9 子串的变量扩展
模式匹配变量用来在串首或串尾截掉串的某一特定部分。这些操作符最常见的用法是从路径头或尾删除路径名元素。如表13-19 所示。
表 13-19 变量扩展子串
表 达 式 |
功 能 |
${ 变量 % 模式 } |
将变量值的尾部与模式进行最小匹配,并将匹配到的部分删除 |
${ 变量 %% 模式 } |
将变量值的尾部与模式进行最大匹配,并将匹配到的部分删除 |
${ 变量 # 模式 } |
将变量值的头部与模式进行最小匹配,并将匹配到的部分删除 |
${ 变量 ## 模式 } |
将变量值的头部与模式进行最大匹配,并将匹配到的部分删除 |
${# 变量 } |
替换为变量中的字符个数。如果是 * 或 @ ,长度则是位置参量的个数 |
范例 13-65
1 $ pathname="/usr/bin/local/bin"
2 $ echo ${pathname%/bin*}
/usr/bin/local
说明
1. 给局部变量 pathname 赋值 /usr/bin/local/bin 。
2. % 删除路径名尾部包含模式 /bin ,后跟零个或多个字符的最小部分。即删除 /bin 。
范例 13-66
1 $ pathname="usr/bin/local/bin"
2 $ echo ${pathname%%/bin*}
/usr
说明
1. 给局部变量 pathname 赋值 /usr/bin/local/bin 。
2. %% 删除路径名尾部包含模式 /bin ,后跟零个或多个字符的最大部分。即删除 /bin/local/bin 。
范例13-67
1 $ pathname=/home/lilliput/jake/.bashrc
2 $ echo ${pathname#/home}
/lilliput/jake/.bashrc
说明
1. 给局部变量 pathname 赋值 /home/liliput/jake/.bashrc 。
2. # 删除路径名头部包含模式/home 的最小部分。路径变量开头的/home 被删除。
范例 13-68
1 $ pathname=/home/lilliput/jake/.bashrc
2 $ echo ${pathname##*/}
.bashrc
说明
1. 给局部变量 pathname 赋值 /home/liliput/jake/.bashrc 。
2. ## 删除路径名的头部包含零个或多个字符,直到并包括最后一个斜杠的最大部分。即从路径变量中删除 /home/liliput/jake/ 。
范例13-69
1 $ name="Ebenezer Scrooge"
2 $ echo ${#name}
16
说明
1. 给变量 name 赋值 Ebenezer Scrooge 。
2. ${#variable} 语法显示赋给变量 name 的字符串中字符的个数。字符串 Ebenezer Scrooge 中有 16 个字符。
13.10.10 位置参量
这组专用内置变量常常被称为位置参量,通常被shell 脚本用来从命令行接收参数,或者被函数用来保存传给它的参数。这组变量之所以被称为位置参量,是因为引用它们要用到1 、2 、3 等数字,这些数字分别代表它们在参数列表中的相应位置。请参见表13-20 。
表 13-20 位置参量
表 达 式 |
功 能 |
$0 |
指代当前 shell 脚本的名称 |
$1-$9 |
代表第 1 个到第 9 个位置参量 |
${10} |
第 10 个位置参量 |
$# |
其值为位置参量的个数 |
$* |
其值为所有的位置参量 |
$@ |
除了被双引号引用的情况,含义与 $* 相同 |
"$*" |
其值为 "$1 $2 $3" |
"$@" |
其值为 "$1" "$2" "$3" |
shell 脚本名存在变量$0 中。位置参量可以用set 命令来设置,重置和复位。
范例 13-70
1 $ set punky tommy bert jody
$ echo $* # Prints all the positional parameters
punky tommy bert jody
2 $ echo $1 # Prints the first position
punky
3 $ echo $2 $3 # Prints the second and third position
tommy bert
4 $ echo $# # Prints the total number of positional parameters
4
5 $ set a b c d e f g h i j k l m
$ print $10 # Prints the first positional parameter followed by a 0
a0
$ echo ${10} ${11} # Prints the 10th and 11th positions
j k
6 $ echo $#
13
7 $ echo $*
a b c d e f g h i j k l m
8 $ set file1 file2 file3
$ echo /$$#
$3
9 $ eval echo /$$#
file3
10 $ set -- # Unsets all positional parameters
说明
1. set 命令给位置参量赋值。专用变量 $* 包含所有的位置参量。
2. 显示第 1 个位置参量的值, punky 。
3. 显示第 2 和第 3 个位置参量的值, tommy 和 bert 。
4. 专用变量 $# 的值是当前已设置的位置参量的个数。
5. set 命令复位所有的位置参量。原来的位置参量集被清除。要打印 9 以上的任意位置参量,就要用花括号把两个数字括起来。否则,就打印第一个位置参量的值,后跟另一个数。
6. 位置参量个数现在是 13 。
7. 显示所有位置参量的值。
8. 美元符被转义, $# 是参数个数。 echo 命令显示 $3 ,一个美元符号后跟位置参量的个数。
9. 执行命令之前, eval 命令对命令行进行第二次解析。第一次由 shell 解析,将输出 $3 。第二次由 eval 解析,显示 $3 的值,即 file3 。
10. 带 -- 选项的 set 命令清除或复位所有的位置参量。
13.10.11 其他特殊变量
shell 有一些由单个字符组成的特殊变量。在字符前面加上美元符就能访问变量中保存的值。如表13-21 所示。
表 13-21 特殊变量
变 量 |
含 义 |
$ |
当前 shell 的 PID |
- |
当前的 sh 选项设置 |
? |
已执行的上一条命令的退出值 |
! |
最后一个进入后台的作业的 PID |
范例 13-71
1 $ echo The pid of this shell is $$
The pid of this shell is 4725
2 $ echo The options for this shell are $–
The options for this shell are imh
3 $ grep dodo /etc/passwd
$ echo $?
1
4 $ sleep 25&
4736
$ echo $!
4736
说明
1. 变量 $ 保存这个进程的 PID 值。
2. 变量 – 列出当前这个交互式 bash shell 的所有选项。
3. grep 命令在 /etc/passwd 文件中查找字符串 dodo 。变量?保存了上一条被执行的命令的退出状态。由于 grep 返回的值是 1 ,因此可以假定 grep 的查找失败了。退出状态 0 代表成功退出。
4. 变量!保存上一条被放入后台的命令的 PID 号。 sleep 命令后面的 & 把命令发到后台。