变量在编程语言中用来表示数据,它本身只是一个标记,指向数据在计算机内存中的一个或一组地址。变量通常出现在算术运算、数量操作以及字符串解析中。
变量替换
变量名是其所指向值的一个 占位符
,而引用变量值的过程则被称为 变量替换
。使用 $var
来获取变量 var
的值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| #!/bin/bash
a=375 hello=$a echo hello echo $hello echo ${hello} echo "$hello" echo "${hello}" echo
hello="A B C D"
echo $hello
echo "$hello"
echo '$hello' echo
hello= echo "\$hello (null value) = $hello" echo
var1=21 var2=22 var3=33 echo "var1=$var1 var2=$var2 var3=$var3" echo
numbers="one two three" other_numbers="1 2 3"
mixed_bas=2\ ---\ Whatever
echo "numbers=$numbers" echo "other_numbers=$other_numbers" echo "$mixed_bas"
echo "uninit_var=$uninit_var" uninit_var= echo "uninit_var=$uninit_var" uninit_var=23 unset uninit_var echo "uninit_var=$uninit_var" echo
exit 0
|
- 变量仅仅在声明、赋值、unset(删除)、export(导出)、
(())
算术运算、或者代表一个信号时,才不需要 $
前缀
- 强烈注意,在变量赋值的前后一定不要有空格
- 注意
$hello
与 "$hello"
的区别,在 ""
内引用变量可以保留变量内的空白字符
$hello
与 ${hello}
也是有区别,前者在某些上下文中将引起错误,为了安全,推荐使用后者
- 单引号内会禁用掉变量的引用,
$
不再具有特殊含义
- 使用空白符分隔,可以在一行内对多个变量进行赋值,但不建议这么做
- 如果变量值中包含有空白字符,变量值必须通过引号进行应用,或者也可以通过
\
转义空白字符
- 未初始的变量、只声明而不初始化的变量、unset 的变量,其值都为空值
一个未初始化或者未被赋值的变量为空值(null value),注意 null value
并不是 0
在赋值前使用变量可能会导致错误,但是在算术运算中使用未赋值变量是可行的。
变量赋值
最常见的变量赋值是通过 =
赋值操作符来实现(=
前后没有空格)。当然在某些上下文中,=
也可以用作比较操作符,此时需要注意区分。除此之外,也可以在 let
、read
for
循环等中进行变量赋值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| #!/bin/bash
echo
a=789 echo "The value of \"a\" is $a"
let a=16+5 echo "The value of \"a\" is $a"
for a in 7 8 9 11 do echo -n "$a " done echo
echo -n "Enter value: " read a echo "The value of \"a\" is $a"
exit 0
|
下面演示了比较特殊的变量赋值,即将命令的执行结果赋值给变量:
1 2 3 4 5 6 7 8 9 10 11 12
|
hello
total 8 -rw-r--r-- 1 root root 226 May 25 10:36 assign_var.sh -rw-r--r-- 1 root root 637 May 25 10:11 var.sh
total 8 -rw-r--r-- 1 root root 226 May 25 10:36 assign_var.sh -rw-r--r-- 1 root root 637 May 25 10:11 var.sh
|
还是要注意这里 $a
和 "$a"
的区别,前者会将多余的空白符都移除,而后者则会保留所有的空白符。
出了使用反引号进行命令替换,也可以使用 $(...)
来进行命令替换,它是一种更新的形式:
1 2 3 4 5 6 7 8
|
total 8 -rw-r--r-- 1 root root 226 May 25 10:36 assign_var.sh -rw-r--r-- 1 root root 637 May 25 10:11 var.sh
total 8 -rw-r--r-- 1 root root 226 May 25 10:36 assign_var.sh -rw-r--r-- 1 root root 637 May 25 10:11 var.sh
|
Bash 弱类型变量
不同于其他编程语言,Bash 并不区分变量的类型。本质上,Bash 变量都是字符串。但是依赖于上下文,Bash 也允许对变量执行比较和算术操作。决定这些的关键因素是:变量值是否只包含数字。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
| #!/bin/bash
a=12345 let "a+=1" echo "a=$a"
b=${a/23/BB} declare -i b echo "b=$b"
let "b+=1" echo "b=$b"
c=BB34 echo "c=$c" d=${c/BB/23} echo "d=$d"
let "d+=1" echo "d=$d" echo
e='' echo "e=$e" let "e+=1"
echo "e=$e"
echo "f=$f" let "f+=1"
echo "f=$f"
let "f/=$unit_var"
let "f/=0"
exit $?
|
- 对于一个包含非数字的变量,即使使用
declare -i
将它声明为整型,也无法进行算术操作
- 对于一个空变量或者未声明的变量,可以对其进行算术操作,其行为就如果该变量的初始值为 0 一样(但是有些情况也不是这样,例如上面的
f/=$unit_var
,$unit_var
并没有当做 0)
Bash 的弱变量使得编程更加灵活、更加容易,但也容易造成一些错误,需要额外注意。
特殊的变量类型
局部变量
局部变量是指在代码块或者函数内才可见的变量,关于局部变量,后面在讲解函数时还会继续介绍。
环境变量
环境变量可以改变用户接口和 shell 的行为。一般情况下,每个进程都有自己的环境,也就是一组该进程可以访问到的变量,shell 也无不例外
- 每次当 shell 启动时,都会创建它自己的环境变量。改变或添加环境变量,将导致 shell 更新它的环境
- 子进程会继承父进程的环境变量
- 分配给环境变量的空间是有限的
如果一个脚本设置了环境变量,那么这些环境变量需要被 导出
,即通知脚本所在的环境做出相应的更新,可以通过 export 命令进行 导出
。脚本只能将变量导出到子进程,子进程不能将变量传递会给父进程。
位置参数
位置参数
就是从命令行中传递给脚本的参数:$0, $1, $2...
- $0:脚本文件的名字;
- $1:第一个参数;
- $2:第二个参数;
- 以此类推; 如果是
$9
以后,就需要使用花括号了:${10}, ${11}, ${12}...
$*
和 $@
表示所有的位置参数
$#
:表示传到脚本中的位置参数的个数(不包含脚本名)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
|
MIN_PARAS=10
echo echo "The name of script is $0" echo "The script is `basename $0`"
if [ -n "$1" ]; then echo "The #1 is $1" fi
if [ -n "$2" ]; then echo "The #2 is $2" fi
if [ -n "${10}" ]; then echo "The #10 is ${10}" fi
echo "-----------" echo "All the command-line parameters are: "$*""
if [ $# -lt "$MIN_PARAS" ]; then echo echo "The script needs at least $MIN_PARAS command-line arguments, current is $#!" fi
echo
exit 0
|
1 2 3 4 5 6 7 8 9 10
|
The name of script is ./pos_para.sh The script is pos_para.sh The The ----------- All the command-line parameters are: 1 2 3
The script needs at least 10 command-line arguments, current is 3!
|
在位置参数中,使用大括号助记符,可以以一种简单的方式来访问传入脚本的最后一个参数:
1 2 3 4 5 6
| args=$# last_arg=${!args} echo $last_arg
last_arg=${!#} echo $last_arg
|
有时候脚本可以通过调用时的文件名来执行不同的操作,要实现该效果,需要检查 $0
,同时通过符号链接产生多个符号链接。如下是一个示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| #!/bin/bash
E_NOARGS=95
if [ -z $1 ]; then echo "Usage: `basename $0` [domain-name]" exit $E_NOARGS fi
case `basename $0` in "wh" ) whois $1@whois.tucows.com;; "wh-ripe" ) whois $1@whois.ripe.net;; "wh-apnic" ) whois $1@whois.apnic.net;; "wh-cw" ) whois $1@whois.cw.net;; * ) echo "Usage: `basename $0` [domain-name]";; esac
|
shift
可以将全体位置参数向左移动一位,重新赋值。例如 $1 <--- $2
,$2 <--- $3
,以此类推。注意 $0
始终保持不变,而原先的 $1
值则消失了。
1 2 3 4 5 6 7 8 9 10 11 12
| #!/bin/bash
until [ -z $1 ]; do echo -n "$1" shift done
echo
echo "after shift, the #2 is $2" exit
|
shift 命令也可以带一个参数来指明一次移动多少位:
1 2 3 4 5 6 7 8
| #!/bin/bash
shift 3
echo "$1"
exit 0
|
shift 命令也可以应用于函数中,使用方法是类似的。