Bash 1 变量
Table of Contents
1 基本变量
Bash 量没有数据类型的概念,所有变量类型和值类型都是字符串。
1.1 创建变量
变量命名规则:
- 由字母、数字和下划线组成。
- 第一个字符不能是数字。
- 不能用标点和空格。
创建方法:
# 等号两边无空格,赋值
variable=value
# 等号两边有空格,判断
var1 = var2
# 变量值有空格,要用 "" 包起来
variable="value_part1 value_part2"
创建变量的例子:
# 例子
a=z # 变量 a 赋值为字符串 z
b="a string" # 变量值包含空格,必须放在引号内
c="a string and $b" # 变量值内可以引用其他变量的值
d="\t\ta string\n" # 变量值内可以使用转义字符
e=$(ls -l foo.txt) # 变量值可以是命令的执行结果
f=$((5 * 7)) # 变量值可以是数学运算的结果
1.2 读取变量
1.2.1 读取变量值
在变量名前加 $
即可。
Bash 每遇到 $ 就会将其后的一个单词作为变量名并读取其值,若该变量名对应的变量不荐在,则输出空字符。
$ 在 Bash 里有特殊的含义,所以在作为美元符号时要小心:
# 命令本意是输出 $100 # 但 Bash 会将 $1 解释为变量,而 $1 为空,按空字符串处理 # $100 就变成了 00 $ echo The total is $100.00 The total is 00.00
# 若要使用 $ 原义,需要写成 \$ $ echo The total is \$100.00 The total is 100.00
当变量名与其它字符连用时,需要用 {}
包围变量名:
$ a=foo $ echo $a_file $ echo ${a}_file foo_file
如果值本身也是变量,使用 ${!varname}
可以读取最终的值 ( ! 表示只向下解析一层 ):
$ var=USER $ echo ${!var} lsz
如果变量值包含连续空格、制表符或换行符,最好放在双引号里面读取:
$ a="1 2 3" $ echo $a 1 2 3 $ echo "$a" 1 2 3
1.2.2 读取变量长度
${#var}
获取 var
变量字符串化后的长度。
$ var=123 $ echo ${#var} 3 $ var="a b c" $ echo ${#var} 5
1.3 修改变量值
变量可以重复赋值,后面的赋值会覆盖前面的赋值:
$ foo=1 $ echo $foo;foo=2 # 一行内有多个语句,必须用 ; 分隔 1 $ echo $foo 2
1.4 删除基本变量
unset
命令用来删除变量。
unset <var_name>
它不是很有用。因为 不存在的 Bash 变量一律按空字符串处理 ,所以变量被删除后,还是可以被读取为空字符串。
所以, 要删除一个变量,也可以将这个变量设成空字符串 。
# 删除了变量 foo 的 2 种写法
foo=''
foo=
2 数组变量
Bash 只支持一维数组 ( one-dimensional indexed array ),不支持高维数组。
2.1 创建数组
# 逐个赋值
arr[0]=val0
arr[1]=val1
arr[2]=val2
# 一次性赋值
arr=(val1 val2 val3 ... valn)
# 等同于
arr=(
val1
val2
val3
...
valn
)
# 指定位置赋值
arr=(a b c)
# 等同于
arr=([2]=c [0]=a [1]=b)
# 又比如
days=(Sun Mon Tue Wed Thu Fri Sat)
days=([0]=Sun [1]=Mon [2]=Tue [3]=Wed [4]=Thu [5]=Fri [6]=Sat)
# 只为某些位置赋值,其它留空
# 比如,hatter 是 0 号位,duchess 是 5 号位,alice 是 6 号位
names=(hatter [5]=duchess alice)
# 通配符赋值
# 将当前目录的所有 MP3 文件,放进一个数组
$ mp3s=( *.mp3 )
# 将用户的命令行输入,存入一个数组 $ read -a dice la lb lc ld # 键盘输入 $ declare -p dice declare -a dice=([0]="la" [1]="lb" [2]="lc" [3]="ld")
2.2 读取数组
2.2.1 读取单个元素
${array[i]}
可获取单个值, i
是索引。
$ array[0]=a $ echo ${array[0]} a # 大括号不可少,否则 Bash 会把 [i] 按原样输出 $ echo $array[0] a[0]
数组名 arr
默认对应 arr[0]
:
$ declare -a arr $ arr=A $ echo ${arr[0]} A $ arr=(1 2 3) $ echo ${arr} 1 $ echo $arr 1
2.2.2 读取所有元素
# 读取所有值 $ arr=(a b c d e f) $ echo ${arr[@]} a b c d e f
# 遍历数组 for item in "${arr[@]}"; do echo $item done # "${names[@]}" 的 "" 一定要加上,否则 $ activities=( 1 "2 3" 4 "5 6" 7 ) $ for act in ${activities[@]}; \ do \ echo "Activity: $act"; \ done Activity: 1 Activity: 2 Activity: 3 Activity: 4 Activity: 5 Activity: 6 Activity: 7
# ${arr[@]} 和 ${arr[*]} 有区别 # ${arr[@]} 把数组的每一个元素都创建为一个参数 $ arr=(1 2 3) $ for item in "${arr[@]}"; \ do \ echo "example.$item" \ done example.1 example.2 example.3 # ${arr[*]} 只创建了一个参数,即数组整体 $ for item in "${arr[*]}"; \ do \ echo "example.$item" \ done example.1 2 3
2.2.3 读取某段元素
${array[@]:position:length}
命令可以提取数组元素。
$ food=( apples bananas cucumbers dates eggs fajitas grapes ) $ echo ${food[@]:1:1} bananas $ echo ${food[@]:1:3} bananas cucumbers dates
2.2.4 获取元素数量
${#var[@]}
或 ${#var[*]}
获取数组 var
中的元素个数。
$ var=("a233333" "b" "c") $ echo ${#var[@]} 3
2.2.5 获取元素索引
${!arr[@]}
或 ${!arr[*]}
,可以返回数组的元素序号,即哪些位置是有值的:
$ arr=([5]=a [9]=b [23]=c) $ echo ${!arr[@]} 5 9 23 $ echo ${!arr[*]} 5 9 23
利用这个方法,可以通过 for 循环遍历数组:
arr=(a b c d)
for i in ${!arr[@]};do
echo ${arr[i]}
done
2.3 修改数组
2.3.1 数组拷贝
# 数组拷贝 $ hobbies=( "${arr[@]}" ) # 可以为新数组添加元素 $ hobbies=( "${arr[@]}" 10 11 )
2.3.2 追加数组元素
+=
运算符能够把值追加到数组末尾:
$ arr=(a b c) $ echo ${arr[@]} a b c $ arr+=(d e f) $ echo ${arr[@]} a b c d e f
2.4 删除数组元素与数组
2.4.1 删除数组元素与数组
unset
命令可以删除一个数组元素或数组。
$ arr=(a b c d e f) $ echo ${arr[@]} a b c d e f $ unset arr[2] $ echo ${arr[@]} a b d e f $ unset arr $ echo ${arr[@]} <--no output-->
2.4.2 隐藏数组元素
将某个元素设为空值,可以从返回值中隐藏这个元素。
$ arr=(a b c d e f) $ arr[1]='' $ echo ${arr[@]} a c d e f
注意, 这里是隐藏,而不是删除,因为这个元素仍然存在,只是值变成了空值。
$ foo=(a b c d e f) $ foo[1]='' $ echo ${#foo[@]} 6 $ echo ${!foo[@]} 0 1 2 3 4 5
2.5 关联数组
关联数组使用字符串而不是整数作为数组索引,且必须用 declare -A <array_name>
创建。
declare -A colors
colors["red"]="#ff0000"
colors["green"]="#00ff00"
colors["blue"]="#0000ff"
关联数组的操作方式,几乎与整数索引数组相同。
3 特殊变量
3.1 基础特殊变量
$?
: 上一个命令的退出码。返回值是 0,表示上一个命令执行成功;不是 0,表示上一个命令执行失败。
$ ls doesnotexist ls: doesnotexist: No such file or directory $ echo $? 1
$$
: 当前 Shell 的进程 ID。
$ echo $$ 10662
# 可以用来命名临时文件 LOGFILE=/tmp/output_log.$$
$_
: 为上一个命令的最后一个参数。
$ grep dictionary /usr/share/dict/words dictionary $ echo $_ /usr/share/dict/words
$!
: 最近一个后台执行的异步命令的进程 ID。
$ firefox & [1] 11064 $ echo $! 11064
$0
: 在命令行直接执行时是当前 Shell 的名称。在脚本中执行时是脚本名。
$ echo $0 bash
$-
: 当前 Shell 的启动参数。
$ echo $- himBHs
$@
: 脚本的所有参数值。
$#
:脚本的参数数量。
3.2 创建特殊变量
declare 命令可以声明一些特殊类型的变量,为变量增加一些限制:
declare option variable=value
declare 命令如果用在函数中,声明的变量只在函数内部有效,等同于 local 命令。
declare 命令不带任何参数时,输出当前环境的所有变量,包括函数在内,等同于不带有任何参数的 set 命令。
declare 命令的主要参数如下:
-a
声明数组变量。声明后变量可以按数组处理。-A
声明关联数组变量。声明后变量可以关联按数组处理。-f
输出所有函数的定义。-F
输出所有函数名。-i
声明整数变量。-l
声明变量为小写字母。-p
查看变量信息。对于未定义的变量,会提示找不到。如果不提供变量名,declare -p
输出所有变量的信息。-r
声明只读变量。创建后无法改变变量值,也不能删除 ( 执行 unset ) 变量。变量会一直存在到 Shell 进程关闭。等同于 readonly 命令。-u
声明变量为大写字母。-x
该变量输出为环境变量。等同于 export 命令。
4 预定义环境变量
4.1 PS1
命令提示符通常是 $,对于 root 用户来说是 #。这个符号是环境变量 PS1
决定的。
用户可以自行修改这个环境变量的值来自定义命令提示符。
命令提示符的定义可以包含特殊的转义字符:
\a
: 响铃,计算机发声一次。\d
: 以星期、月、日格式表示当前日期,例如 Mon May 26 。\h
: 本机的主机名。\H
: 完整的主机名。\j
: 运行在当前 Shell 会话的工作数。\l
: 当前终端设备名。\n
: 一个换行符。\r
: 一个回车符。\s
: Shell 的名称。\t
: 24 小时制的 hours:minutes:seconds 格式的当前时间。\T
: 12 小时制的当前时间。\@
: 12 小时制的 AM/PM 格式的当前时间。\A
: 24 小时制的 hours:minutes 格式的当前时间。\u
: 当前用户名。\v
: Shell 的版本号。\V
: Shell 的版本号和发布号。\w
: 当前的工作路径。\W
: 当前目录名。\!
: 当前命令在命令历史中的编号。\#
: 当前 shell 会话中的命令数。\$
: 普通用户显示为 $ 字符,根用户显示为 # 字符。\[
: 非打印字符序列的开始标志。\]
: 非打印字符序列的结束标志。
比如 $PS1
值为 \u@\h:\w\$
,显示效果为 [email protected]:~$
。
也可以为 PS1 加入文字颜色定义 ( \033
可用 \e
代替 ):
\033[0;30m
黑色\033[1;30m
深灰色\033[0;31m
红色\033[1;31m
浅红色\033[0;32m
绿色\033[1;32m
浅绿色\033[0;33m
棕色\033[1;33m
黄色\033[0;34m
蓝色\033[1;34m
浅蓝色\033[0;35m
粉红\033[1;35m
浅粉色\033[0;36m
青色\033[1;36m
浅青色\033[0;37m
浅灰色\033[1;37m
白色
和文字背景颜色定义 ( \033
可用 \e
代替 ):
\033[0;40m
蓝色\033[1;44m
黑色\033[0;41m
红色\033[1;45m
粉红\033[0;42m
绿色\033[1;46m
青色\033[0;43m
棕色\033[1;47m
浅灰色
注意: 必须把把颜色信息放在 \[
和 \]
中间,否则长于一行的命令将不会自动换行。
比如 PS1='\[\033[0;31m\]<\u@\h \W>\$'
则显示红色的命令提示符,但这也会导致后面命令变成红色。可以在结尾添加另一个特殊代码 \[\033[00m\]
,表示将其后的文本恢复到默认颜色。所以应该写成 PS1='\[\033[0;31m\]<\u@\h \W>\$\[\033[00m\]'
。
比如 PS1='\[\033[0;41m\]<\u@\h \W>\$\[\033[0m\] '
这是一个带红色背景的命令提示符。
4.2 PS2 PS3 PS4
环境变量 PS2 是输入多行命令时的行首提示符,默认为 >
。
$ echo "hello > world"
环境变量 PS3 是使用 select 命令时,系统输入菜单的提示符。
环境变量 PS4 默认值为 +
。执行 bash -x {script_name}.sh
时,脚本的每一行命令被执行前都会被输出到终端,并且每行行首出现 PS4 定义的提示符。
$ cat>test.sh<<'EOF' #!/bin/bash echo "hello world1" echo "hello world2" echo "hello world3" EOF $ bash -x test.sh + echo 'hello world1' hello world1 + echo 'hello world2' hello world2 + echo 'hello world3' hello world3