在 Shell 中 $
字符可以用于参数扩展,算术扩展和命令替换。可以根据需要使用它来操作和扩展变量,而无需使用 sed
、awk
等外部命令。
声明变量的语法如下:
# 语法
变量名=变量值
# 示例
msg="hello world"
获取变量值的语法如下:
# 语法一,使用引号引起来是为了避免因为变量中有空格导致出现错误
echo "$变量名"
# 示例一
echo "$msg"
# 语法二,printf 命令也可以输出内容,但不会自动换行,需要通过转义符 \n 进行换行
printf "$变量名"
# 示例
printf "$msg\n"
如果要对变量进行扩展,就可以使用 ${}
语法,格式如下:
# 语法,不进行变量扩展时等价于 "$变量名"
${变量名}
# 示例
echo "${msg}"
我们可以为变量设置默认值,语法格式如下:
# 语法
${变量名:-默认值}
${变量名:=默认值}
# 示例
res=${msg:-"hello world"}
res=${msg:="hello world"}
关于它们的使用及区别,详情可参考:Linux拓展之Shell默认变量值。
我们可以设置如果变量未定义或者位置参数未传递,则可以用如下语法停止执行脚本,以免报错。命令格式如下:
# 语法
# 如果变量未定义
${变量名?变量未定义输出的提示信息}
# 如果变量未定义或者为空字符串
${变量名:?变量未定义输出的提示信息}
# 未传递位置参数,通常用在脚本或函数中
${位置参数名:?未传递位置参数输出的提示信息}
# 示例
# 如果变量未定义
res=${msg?"变量未定义"}
# 如果变量未定义或者为空字符串
res=${msg:?"变量未定义或为空"}
# 未传递位置参数,通常用在脚本或函数中,$1、$2 等表示接收第 1、2 个参数
res=${1:?"未传递位置参数"}
# 提示信息中也可以使用变量扩展
info="未定义的变量"
res=${msg:?"Error: ${info}."}
如果要查找一个字符串变量的长度,语法格式如下:
# 语法
${#变量名}
# 示例
msg="hello world"
len=${#msg}
echo $len
可以移除字符串变量中前面的子串(从前往后)。语法格式如下:
# 语法:可以从变量前面开始移除匹配模式匹配到的所有字符
# 删除匹配模式匹配到的最短部分,非贪婪匹配
${变量名#匹配模式}
# 删除匹配模式匹配到的最长部分,贪婪匹配
${变量名##匹配模式}
# 示例,获取路径所表示的文件后缀
path="/root/src/tar/test.tar.gz"
echo "${path#*.}" # 非贪婪匹配,* 属于通配符,匹配第一个 . 字符前面的所有内容,即会删除第一个 . 字符之前的所有内容,包括 . 字符本身
# 示例,只获取如下路径所表示的文件名
path="/root/src/tar/test.tar.gz"
echo "${path##*/}" # 贪婪匹配,* 属于通配符,匹配最后一个 / 字符前面的所有内容,即会删除最后一个 / 字符之前的所有内容,包括 / 字符本身
可以移除字符串变量中后面的子串(从后往前)。语法格式如下:
# 语法:可以从变量后面开始移除匹配模式匹配到的所有字符
# 删除匹配模式匹配到的最短部分,非贪婪匹配
${变量名%匹配模式}
# 删除匹配模式匹配到的最长部分,贪婪匹配
${变量名%%匹配模式}
# 示例,获取路径所表示的文件父目录
path="/root/src/tar/test.tar.gz"
echo "${path%/*.tar.gz}" # 非贪婪匹配,* 属于通配符,匹配 /test.tar.gz,会删除该字符串获取到该文件的父目录
# 示例,只获取所表示的文件名而去除掉后缀
file="test.tar.gz"
echo "${file%%.*}" # 贪婪匹配,* 属于通配符,会从后往前找到最后一个 . 字符,然后删除 . 字符及之后的所有字符,留下文件名
可以查找到旧字符串然后替换成新字符串(可以替代 sed
命令)。语法格式如下:
# 语法,只会替换第一次匹配成功的字符串
${变量名/旧字符串匹配模式/新字符串}
# 语法,替换所有匹配成功的字符串
${变量名//旧字符串匹配模式/新字符串}
# 示例
var="hello world, hello linux."
# 替换变量 var 中的 hello 为 HELLO
out=${var/hello/HELLO}
echo $out
echo $var
# 替换变量 var 中的 world 为 java
out=${var/world/java}
echo $out
echo $var
# 替换变量 var 中的所有 hello 为 HELLO
out=${var//hello/HELLO}
echo $out
echo $var
# 对文件进行重命名
path="/root/test.txt"
cp "${path}" "${path/.txt/.txt.bak}"
注:会返回修改后的结果,而不是对原变量进行修改。
还可以提取子串,表示从 offset
指定的字符开始扩展到参数的最大长度字符。语法格式如下:
# 语法
# 提取从第 offset 个字符开始到字符串结尾的所有字符
${parameter:offset}
# 提取从第 offset 个字符开始的 length 个字符
${parameter:offset:length}
${variable:position}
# 示例1,去除多余的斜线
file="/data.tar.gz"
echo ${file:1}
# 示例2,提取指定个数的字符
name="www.baidu.com"
echo ${name:4:5}
注:
offset
是从字符串的第 1 个字符开始的。
可以获取名称以指定前缀开头的所有变量名称。语法格式如下:
# 语法
${!指定变量前缀匹配模式}
# 示例
name1="唐僧"
name2="孙悟空"
name3="猪八戒"
echo "${!name*}"
可以将字母转换成大写或小写。语法格式如下:
# 语法,将第一个字符转换为大写
${变量名^}
# 语法,将所有字母都转换成大写
${变量名^^}
# 语法,将第一个字符转换为小写
${变量名,}
# 语法,将所有字母都转换成小写
${变量名,,}
# 语法,仅转换第一个字符为小写
${变量名,指定第一个字符}
# 示例,将第一个字符转换为大写
msg="hello"
echo ${msg^}
# 示例,将所有字母都转换成大写
echo ${msg^^}
# 示例,将第一个字符转换为小写
msg="HELLO"
echo ${msg,}
# 示例,将所有字母都转换成小写
echo ${msg,,}
# 示例,仅第一个字符是 H 则转换它
echo ${msg,H}
所有方便的 bash 参数替换运算符如下表:
语法 | 说明 |
---|---|
${parameter:-defaultValue} |
获取默认 shell 变量值 |
${parameter:=defaultValue} |
设置默认 shell 变量值 |
${parameter:?"Error Message"} |
如果未设置参数,则显示错误消息 |
${#var} |
查找字符串的长度 |
${var%pattern} |
从最短的后端(末端)模式中移除 |
${var%%pattern} |
从最长的后端(末端)图案中移除 |
${var:num1:num2} |
子串 |
${var#pattern} |
从最短的正面图案中移除 |
${var##pattern} |
从最长的正面图案中移除 |
${var/pattern/string} |
查找和替换(仅替换第一次出现) |
${var//pattern/string} |
查找并替换所有匹配项 |
${!prefix*} |
扩展到名称以前缀开头的变量的名称 |
${var,} |
将第一个字符转换为小写。 |
${var,pattern} |
如果匹配成功,才将第一个字符转换为小写。 |
${var,,} |
将所有字符转换为小写。 |
${var,,pattern} |
如果匹配成功,才将所有字符转换为小写。 |
${var^} |
将第一个字符转换为大写。 |
${var^pattern} |
如果匹配成功,才将第一个字符转换为大写。 |
${var^^} |
将所有字符转换为大写。 |
${var^^pattern} |
如果匹配成功,才将所有字符转换为大写。 |
参考资料: