Shell编程基础
变量
定义、使用、删除
定义变量
- 定义时不加
$
符号 - 变量名和等号之间不能有空格
- 变量名只能由英文字母、数字、下划线,且不以数字开头, 不能用bash中的关键字
- 已经定义变量可以重新定义
- 定义时不加
使用变量
- 即可使用, 未定义变量直接使用不报错,返回空值
{}
可选,但是{}
能够明确定义变量名范围,帮助阅读、 解释器执行
匿名变量
- 可以认为所以语句(命令)的执行结果都存储在一个匿名
变量中,可以在其之前加上
$
获取其结果
- 可以认为所以语句(命令)的执行结果都存储在一个匿名
变量中,可以在其之前加上
readonly
:设置变量为只读变量,更改(重定义)变量报错unset
:删除变量,不能删除只读变量
局部变量
局部变量:在脚本、命令中定义
仅在当前shell实例中有效
- shell变量默认为global,作用域从被定义处开始到脚本 末尾(即使在函数内部定义)
- 显式
local
声明作用域局限于函数内部
其他shell启动的程序不能访问局部变量
环境变量
环境变量:就是shell中的普通变量,只是这些变量往往被进程读取 用于自身初始化、设置
- 狭义:
export
/declare -x
声明的变量,只有这样的变量 才能默认被子进程继承 - 广义;shell中所有的变量(包括局部变量)
环境变量设置
在shell中设置环境变量有两种方式
export
/declare -x
:设置全局(环境)变量- 任何在该shell设置环境变量后,启动的(子)进程都会 继承该变量
- 对于常用、许多进程需要的环境变量应该这样设置
<ENV_NAME>=... cmd
:设置临时环境变量<ENV_NAME>=...
不能被子进程继承,所以必须在其后立刻 接命令- 只对当前语句有效,也不能覆盖同名变量
用途
- 环境变量是某些程序正常运行的必要条件
- 所有程序都能访问环境变量,可用作进程通信
- 在程序中设置环境变量,供其他进程访问变量
- 父进程为子进程设置环境变量,供其访问
Shell变量
Shell变量:shell程序设置的特殊变量,包括环境变量、局部变量, 保证shell的正常运行
$0
:shell执行脚本名- 交互式bash(即普通终端中)该参数为
-bash
- 则
source
执行脚本时,该参数可能非预期
- 则
- 以下shell变量均不考虑
$0
,如- 函数中
$0
也是脚本名 shift
无法跳过该参数
- 函数中
- 交互式bash(即普通终端中)该参数为
$1,..., $9
:向脚本传递的位置参数$@
:脚本、函数参数列表$*
:脚本、函数参数字符串$#
:脚本、函数参数数量$?
:上条命令执行结果- $$$$:脚本进程号
$!
:执行脚本最后一条命令
字符串
拼接
- shell中字符默认为字符串,自动拼接
通配符
*
:匹配任意长度字符串- 不包括
.
、/
,必须显式匹配
- 不包括
?
:匹配一个字符[]
:匹配出现在[]
中的字符1
2ls /[eh][to][cm]*
匹配`/etc`、`/home`等{}
枚举全部
1
2
3
4
5
6mkdir {user1, user2}-{home, bin}
笛卡尔积(字符串连接)
等价于建立`user1-home, user1-bin, user2-home, user2-bin`
echo {1..10}
生成序列
见`for`中`RangeIterator`部分
子串
1 | file=/dir1/dir2/dir3/file.txt.bak |
切片
${<var_name>:n[:m]}
:从第n
开始m
个字符n
、m
非负值n
:从0开始的下标起始m
:切片长度,缺省表示到末尾
n
、m
使用0-
负值表示n
:从0开始的负向下标起始m
:从0开始的负向下标终止
命令 | 解释 | 结果 |
---|---|---|
${file:0:5} |
提取首个字符开始的5个字符 | /dir1 |
${file:5:5} |
提取第5个字符开始的5个字符 | /dir2 |
${file:5} |
提取第5个字符开始至末尾 | /dir2... |
${file:0-5} |
反向计算下标 | t.bak |
${file:0-5:0-1} |
反向计算下标 | t.ba |
${file:5:0-2} |
提取第5个字符开始至-2 下标处 |
/dir2.../t.b |
子串匹配
1 | {<var_name>%<pattern>} |
#
:去掉字符串左边最短pattern##
:去掉字符串左边最长pattern%
:去掉字符串右边最短pattern%%
:去掉字符串右边最长pattern
- 注意:
var_name
前不要变量标志$
- 以上4种模式返回新值,不改变原变量值
- 仅在
pattern
中使用通配符时,最短、最长匹配才有区别
命令 | 解释 | 结果 |
---|---|---|
${file#*/} |
去除首个/ 及其左边 |
dir2/dir3/file.txt.bak |
${file##*/} |
仅保留最后/ 右边 |
file.txt.bak |
${file#*.} |
去除首个. 及其左边 |
txt.bak |
${file##*.} |
仅保留最后. 右边 |
bak |
${file%/*} |
去除最后/ 及其右边 |
/dir1/dir2/dir3 |
${file%%*/} |
去除首个/ 及其右边 |
空值 |
${file%*.} |
去除最后. 及其右边 |
/dir1/dir2/dir3/file.txt |
${file%%*.} |
去除首个. 及其右边 |
/dir1/dir2/dir3/file.txt |
替换
/from/to
:替换首个from
为to
//from/to
:替换全部from
为to
命令 | 解释 | 结果 |
---|---|---|
${file/dir/path} |
替换首个dir 为path |
/path1/dir2/dir3/file.txt.bak |
${file/dir/path} |
替换全部dir 为path |
/path1/path2/path3/file.txt.bak |
默认值替换
-
:变量未设置返回+
:变量设置返回=
:变量未设置返回、设置变量?
:变量未设置输出至stderr:
:以上命令条件包括空值(空值视为未设置)
命令 | 解释 | 示例 | 结果 |
---|---|---|---|
${井<var_name>} |
获取字符串长度 | ${井file} |
27 |
${<var_name>-<default>} |
变量未设置返回默认值 | ${invalid-file.txt.bak} |
file.txt.bak |
${<var_name>:-<default>} |
变量未设置、空值返回默认值 | ${null-file.txt.bak} |
file.txt.bak |
${<var_name>+<default>} |
变量设置返回默认值 | ${file-file.txt.bak} |
fil.txt.bak |
${<var_name>:+<default>} |
变量非空返回默认值 | ${file-file.txt.bak} |
file.txt.bak |
${<var_name>=<default>} |
变量未设置,返回默认值、并设置变量为默认值 | ${invalid=file.txt.bak} |
file.txt.bak |
${<var_name>:=<default>} |
变量未设置、空值返回默认值、并设置变量为默认值 | ${null=file.txt.bak} |
file.txt.bak |
{$<var_name>?<default>} |
变量未设置输出默认值至stderr | {invalid?file.txt.bak} |
file.txt.bak 输出至stderr |
{$<var_name>:?<default>} |
变量未设置、空值输出默认值至stderr | {$null:?file.txt.bak} |
file.txt.bak 输出至stderr |
字符串比较
=, !=, -z, -n
:字符串相等、不相等、为空、非空使用
=
比较变量是否为某字符串时,其中在两侧添加字符 保证=
不为空值,否则若$test
为空值,表达式报错1
2
3if [[ "$text"x = "text"x ]]; then
command
fi
- 比较变量时要在两侧加上双引号
""
,否则可能报错、结果不 符合预期
数组
1 | A=(a b c def) |
取值
[]
:选择数组元素[n]
:返回数组第n个元素[*]
/[@]
:返回数组全部元素
命令 | 解释 | 结果 |
---|---|---|
${A[@]} |
返回全部元素 | a b c def |
${A[*]} |
同上 | 同上 |
${A[0]} |
返回数组第一个元素 | a |
${井A[@]} |
返回数组元素总数 | 4 |
${井A[*]} |
同上 | 同上 |
${井A[3]} |
返回数组第4个元素长度 | 3 |
A[3]=xyz |
设置数组第4个元素值 |
数值
(())
/[]
:在其中执行整数运算let
:执行数值运算
规则
返回的数据结果相当于存储在一个匿名变量中,使用的话需要 在之前加上
$
1
2
3a=5; b=7; c=2;
echo $((a + b * $c))
19$((N#xx))
/$[$#xx]
:将其他进制数据转换为10进制1
2echo $((2#110))
6自增、自减运算可以在
(())
/[]
中直接执行1
2a=5; ((a++)); echo $a;
6
特殊运算符
~
:位与|
:位或^
:位异或>>
:位右移<<
:位左移**
:数值平方+=, ++, -=, --, *=, \=
:自变化运算符
逻辑运算
-eq, -ne, -ge, -le, -lt, -gt
:比较==, !=, >=, <=, <, >
:数值比较
文件
-e
:目标存在-f
:文件为一般文件(非目录、设备)-s
:文件大小非0-d
:目标为目录-b
:文件为块设备(软盘、光驱)-c
:文件为流设备(键盘、modem、声卡)-p
:文件为管道-h
/L
:目标为符号链接-S
:目标为Socket-t
:文件描述符被关联到终端- 一般用于检测脚本的stdin是否来自终端
[ -t 0 ]
,或 输出是否输出至终端[ -t 1 ]
- 一般用于检测脚本的stdin是否来自终端
-r
:目标是否可读权限-w
:目标是否可写权限-x
:目标是否可执行权限-g
:目标是否设置有set-group-id-u
:目标是否设置有set-user-id-k
:目标是否设置sticky bit-O
:用户是否是文件所有者-G
:用户是否属于文件所有组-N
:文件从上次读取到现在为止是否被修改f1 -nt f2
:文件f1
比f2
新f1 -ot f2
:文件f1
比f2
旧f1 -ef f2
:文件f1
、f2
指向相似文件实体(相同的硬链接)