变量在编程语言中用来表示数据,它本身只是一个标记,指向数据在计算机内存中的一个或一组地址。变量通常出现在算术运算、数量操作以及字符串解析中。
 变量替换
变量名是其所指向值的一个 占位符,而引用变量值的过程则被称为 变量替换。使用 $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 命令也可以应用于函数中,使用方法是类似的。