Linux shell 变量详解
shell变量
var_name="runoob",变量名和等号之间不能有空格,因为空格通常用于分隔命令和参数- 使用变量:
$var_name、${var_name},加大括号是为了帮助解释器识别变量的边界。$相当于从变量中取值(解引用),不加$则表示变量本身 - 只读变量:
readonly var_name,变量值不可被改变 - 删除变量:
unset var_name,删除后不能再次使用,不能删除只读变量
变量类型
字符串变量
- 使用单引号
'或双引号"定义,var_name='zmy' var_name="zmy"。
ℹ️
单引号中的任何字符都会原样输出,其中的变量是无效的,单引号字符串内不能出现一个单独的单引号(转义也不行)但可成对出现,作为字符串拼接使用:
var1='zmy_'$var_name'_flm' # 输出 zmy_runoob_flm
var2='zmy_$var_name_flm' # 输出 zmy_$var_name_flm
- 双引号中可以有变量,可以出现转义字符:
var1="Hi, "$var_name"! \n" # 输出 Hi, runoob
var2="Hi, ${var_name}! \n" # 输出 Hi, runoob
- 获取字符串长度:
${#var_name},等价于${#var_name[0]} - 提取子字符串:
${var_name:1:2}输出un - 查找子字符串:
string="runoob is a great site"
echo `expr index "$string" io` # 输出 4
整数变量
declare -i my_int=42
# 使用 (( )) 算术表达式(推荐)
a=2
((a++)) # a 自增 1 → a=3
((a--)) # 自减
((a += 1)) # 等价于 a = a + 1
((a = a + 1))
# 使用 $(( )) 算术扩展
a=2
a=$((a + 1)) # a=3
a=$((a * 2)) # a=6
# 使用 let 命令(较老,不推荐)
a=2
let a=a+1
let "a += 1" # 带空格时需加引号
数组(不支持多维数组)
- 整数索引数组:
my_array=(1 2 3 4 5 6) - 关联数组:
declare -A my_array, my_array['name']='zmy',my_array['age']=30
# 获取数组的某个值
value=${my_array[n]}
# 使用 @ 或 * 获取数组中所有元素
${my_array[@]}
${my_array[*]}
# 使用 ! 获取数组中所有键
${!my_array[@]}
${!my_array[*]}
# 获取数组元素的个数
length=${#my_array[@]};
length=${#my_array[*]}
# 获取单个元素的长度
length=${#my_array[n]}
# 判断关联数组中是否存在键
if [[ -n "${my_array[$key]+exists}" ]]; then
echo "$key 存在"
fi
if [[ -v "my_array[$key]" ]]; then
echo "$key 存在"
fi
# 判断普通数组中是否存在值
[[ "${my_array[*]}" =~ "$value" ]] && echo "存在" || echo "不存在"
mapfile
- 在 Bash 4.0 及以上版本中,
mapfile是一个强大的内置命令,用于将文件或标准输入的内容按行读入数组。它等价于readarray,语法和功能完全一致。
# 如果不指定数组名,数据将默认存储到 MAPFILE 数组中。
mapfile [选项] 数组名 < 输入源
# 或
mapfile [选项] 数组名 文件名
- 常用选项
-n count最多读取 count 行-O origin从数组索引 origin 开始赋值(默认 0)-s count跳过前 count 行-t删除每行末尾的换行符(默认行为)-d DELIM指定行分隔符(默认是换行符)-u fd从文件描述符 fd 读取(默认 0)-C callback每读 callback 行调用一次命令-c quantum与-C搭配,指定调用频率,每读取quantum行执行一次回调(包括当前行)
⚠️
- 回调是在读取过程中触发,不是读取完成后
- 每次回调时,数组只包含当前已读取的行
- 执行回调时,会传递两个参数
$1: 当前正在读取的行号,从 0 开始,$2: 当前正在读取的行内容- 利用回调时的数组长度(等于
$1参数)
内置特殊变量
命令行参数变量
$0脚本名称$1-$9第1-9个位置参数${10}第10个参数(需要大括号)$#参数个数$@所有参数,每个都是独立字符串,如果"$@"则以"$1" "$2" ... "$n"的形式输出所有参数$*所有参数,作为一个字符串,如果是"$*"则以"$1 $2 ... $n"的形式输出所有参数
进程和状态变量
$$当前进程PID$!最后一个后台进程的PID$?上一个命令的退出状态码$_上一个命令的最后一个参数$-当前shell选项标记!!上一条命令
脚本信息变量
$BASHBash的完整路径$BASH_VERSIONBash版本$BASH_VERSINFO[0-6]Bash版本信息数组$BASH_SOURCE当前执行的源文件(脚本)路径$BASH_SUBSHELL子shell层级
执行环境变量
$LINENO当前在脚本中的行号$FUNCNAME当前函数名(数组,[0]是当前函数)$BASH_COMMAND当前正在执行的命令$PIPESTATUS管道中每个命令的退出状态数组$SECONDS脚本运行秒数$RANDOM随机数(0-32767)$REPLYread命令默认读取的变量$OPTARGgetopts的选项参数$OPTINDgetopts的选项索引
行和文件描述符
$COLUMNS终端列数$LINES终端行数$UID当前用户UID$EUID当前有效用户UID$GROUPS用户所属组数组
调试相关变量
$BASH_XTRACEFD用于set -x输出的文件描述符$BASH_LINENO函数调用栈的行号数组$BASH_ARGC函数参数个数数组$BASH_ARGV函数参数值数组
扩展和匹配变量
$IFS内部字段分隔符(默认是空格、制表符、换行)$GLOBIGNORE通配符忽略模式$BASH_REMATCH正则表达式匹配结果数组$BASH_ALIASES别名数组$BASH_CMDS命令哈希表
注释
- 单行注释:
# 这是一个注释 - 多行注释:冒号
:是空命令,内容不会执行
:<<EOF(EOF也可以使用其他符号:COMMENT ' !)
注释内容
注释内容
注释内容
EOF
: '
这是注释的部分。
可以有多行内容。
'
参数扩展
shell命令执行顺序
- 分词 (Tokenization):分割成 tokens:
echo,"当前目录: $PWD",*.txt - 展开 (Expansion):参数展开在这里发生
a. 大括号展开{}
b. 波浪号展开~
c. 参数展开$
d. 命令替换$()
e. 算术展开$(( ))
f. 单词分割
g. 文件名展开* ? [...] - 引用移除 (Quote Removal)
- 命令执行 (Execution)
- 参数扩展提供了多种方式来修改和提取变量的内容,如果
parameter是数字,则是参数扩展;如果parameter是字符串,则是变量扩展;如果parameter是数组,遵循数组的扩展规则;parameter还可以是@, *, #, ?, -等,参考特殊参数的扩展。 - shell 变量扩展发生在命令执行前
# 无引号:Shell 扩展
echo *.txt # Shell 扩展
# 单引号:完全字面
echo '*.txt' # 输出: *.txt
# 双引号:变量扩展,但通配符不扩展
echo "$HOME/*.txt" # 输出: /home/user/*.txt
ℹ️
除了${variable:=word}和${variable::=word}(强制修改变量为word无论原变量是否为空,Bash 4.4+ 新增)之外,其他变量扩展不会修改变量的值,仅是返回扩展结果
-
直接扩展和间接扩展
a=b; b=123;echo ${a}基本扩展,输出结果为becho ${!a}间接参数扩展,输出结果为变量b的值123,${!var}将参数扩展为变量的值,在处理变量名作为字符串时很有用- 如果
b是一个名称引用(nameref),则不会发生间接扩展,还是输出b
-
变量引用
${variable} 或 $variable直接引用变量的值
-
设置默认值
${variable:-word}- 如果变量variable已被设置且非空,则展开为变量的值;否则,展开为word。${variable:=word}- 类似于${variable:-word},但是还会将word的值赋给变量variable。${variable:+word}- 如果变量variable已被设置且非空,则展开为word;否则,什么也不做。${variable:?word}- 如果变量variable已被设置且非空,则展开为变量的值;否则,打印错误消息至标准错误并退出 shell,错误消息包含word
-
字符删除
${variable#pattern}删除variable中pattern匹配的开头最短部分。${variable##pattern}删除variable中pattern匹配的开头最长部分。${variable%pattern}删除variable中pattern匹配的结尾最短部分。${variable%%pattern}删除variable中pattern匹配的结尾最长部分。pattern是 Glob 模式?匹配任何一个字符。*匹配任意数量的字符(包括零个字符)。[...]匹配括号内的任何一个字符。例如,[abc]匹配'a'、'b' 或 'c'。{a,b,c}匹配a 或 b 或 c。
ℹ️
pattern必须能够匹配开头(对于%)或者结尾(对于#),如果只匹配了中间部分则无法删除
- 字符替换
${variable/pattern/string}替换变量值variable的第一次出现的pattern为string。${variable//pattern/string}替换变量值variable中所有出现的pattern为string。${variable/#pattern/string}:如果变量variable值以pattern开头,则将其替换为string${variable/%pattern/string}:如果变量variable值以pattern结尾,则将其替换为string
其中/string部分可省略,表示替换为空,即删除,例如${url//:*}删除:之后的所有内容
-
子字符串截取
${variable:start:length}- 截取变量值variable的子字符串,从索引start开始(从0开始计数),长度为length字符。${variable:start}- 截取变量值variable的子字符串,从索引start开始(从0开始计数)直到末尾。
-
大小写转换
${variable,,}- 将变量值variable转换为小写。${variable^^}- 将变量值variable转换为大写。${parameter^pattern}和${parameter^^pattern}用于将变量值中的匹配部分转换为大写,分别转换第一个匹配和所有匹配。${parameter,pattern}和${parameter,,pattern}用于将变量值中的匹配部分转换为小写,分别转换第一个匹配和所有匹配。
特定操作( Bash 4.4 及以上版本)${variable@operator} operator 取值:
U全大写u首字母大写L全小写K显示变量的赋值语句格式,字符串会被引号包裹Q转义字符生成E转义字符展开P提示符展开A显示变量的声明语句K数组变量名和值k数组变量名和值a返回变量属性值, 表示为一系列标志:-:变量既没有被引号引用,也不是数组。q:变量被单引号引用。Q:变量被双引号引用。x:变量是被解释的。X:变量是被不被解释的。@:变量是数组或者关联数组。A:变量是被赋值的(assigned)。
欢迎大家关注我的微信公众号【扶锐随笔】

浙公网安备 33010602011771号