Shell的变量
本地变量
生效范围为当前shell进程,对当前shell之外的其他shell进程 包括当前shell的子shell进程和父shell进程均无效。可以使用set
查看当前所有变量环境变量
生效范围为当前shell进程及其子进程- 使用
export name=VALUE
和declare -x name=VALUE
创建或转换环境变量
- 使用
局部变量
生效范围为当前shell进程中某函数的作用范围中。使用local name=VALUE
定义局部变量位置变量
用于执行脚本时传参特殊变量
shell内置的特殊变量$0
获取脚本执行时的路径$?
获取上一条指定的执行返回码$*
把传递给脚本的所有参数 视为一个字符串$@
把传递给脚本的所有参数 每一个参数视为每一个独立的字符串$#
传递给脚本的参数数量$$
获取当前shell的进程号$!
获取执行的上一个指令的pid$_
获取上一个执行的命令或脚本的最后一个参数
只读变量
只读变量不能被修改,不能unset销毁readonly name
和declare -r name
创建只读变量
# 变量的引用
[root@stardust ~]# echo $name
[root@stardust ~]# echo ${name}
# 命令结果引用
[root@stardust ~]# echo `date`
[root@stardust ~]# echo $(date)
# 销毁变量
[root@stardust ~]# unset name
Shell的算数运算
shell默认不支持浮点运算,浮点运算需要使用awk
或bc
[root@stardust ~]# let var=num1+num2 # let不会输出结果 需要复制给变量
[root@stardust ~]# echo $[RANDOM%30] # shell内置随机数生成器 1-32767
[root@stardust ~]# echo $((2+3))
[root@stardust ~]# expr 123 + 33 / 3
Shell条件判断
条件测试
test EXPRESSION
[ EXPRESSION ]
[[ EXPRESSION ]]
数值测试
-eq
等于-ne
不等于-lt
小于-le
小于等于-gt
大于-ge
大于等于
字符测试
==/=
等值测试!=
不相等=~
左侧字符是否能被右侧的PATTERN所匹配 只能于[[ ]]
中使用-z "STRING"
若字符为空 为真-n "STRING"
若字符串不为空 为真
文件测试
-e
是否存在 不分类型-s
是否存在且非空文件-b
是否存在且为块设备-c
是否存在且为字符设备-f
是否存在且为普通文件-d
是否存在且为目录-S
是否存在且为套接字-p
是否存在且为管道-L -h
是否存在且为软链接文件-g
是否存在且被设置了sgid-u
是否存在且被设置了suid-k
是否存在且被设置了sticky-r
是否存在且可读-w
是否存在且可写-x
是否存在且可执行-t fd
文件描述符是否打开且与某终端相关-N
文件自上一次被读取后是否被修改(重定向写入)过file1 -ef file2
判断两个文件是否指向同一个设备上的相同inodefile1 -nt file2
判断file1是否比file2时间戳更新file1 -ot file2
判断file1是否比file2时间戳更旧
逻辑运算
&&
-a
与||
-o
或!
非
Shell的语句
if分支语句
# 由上至下匹配,一旦匹配不再执行后面代码
if CONDITION1; then
COMMAND
elif CONDITION2; then
COMMAND
esle
COMMAND
fi
case分支语句
# 由上至下匹配,一旦匹配不再执行后面代码
# PAT部分不支持正则,但是支持glob机制 `*, ?, [], |`等
case 变量引用 in
PAT1|pat1)
分支1
;;
PAT2|pat2)
分支2
;;
*)
默认分支
;;
esac
for循环语句
# 列表生产方式
# [1] 直接给出列表 如 `a d c f`
# [2] 返回列表的命令 如`seq 10`,`ls *`
# [3] 变量引用 `$@, $*`
# [4] glob 如 `{1..10}`
for 变量名 in 列表; do
循环体
done
C语言型结构
# 变量初始化仅在进入循环时执行一次
# 每轮循环结束后会先进行变量修正运算,然后再进行条件判断
for ((变量初始化;条件判断表达式;修正变量表达式)); do
循环体
done
=======================================================================
# demo 求100以内数字的和
#!/bin/bash
sum=0
for ((i=1;i<101;i++));do
((sum=sum+i))
done
echo $sum
简写结构
# 正常结构中的"in 取值列表"可省略,省略时相当于`for n in "$@"`,循环列表为命令行参数列表
# demo 打印传递给脚本的参数
for VAR;do
echo $VAR
done
[root@stardust ~]# sh test.sh a b c d
a
b
c
d
while循环语句
# 若条件为真 则一直执行循环体
while CONDITION; do
循环体
done
遍历文件内容
# 通过输入重定向遍历文件
while read VAR; do
循环体
done < /PATH/TO/FILE
# 通过输出重定向遍历文件
cat /PATH/TO/FILE | while read VAR; do
循环体
done
# until同样支持此用法 不过需要取反`until ! read VAR`
until循环语句
# 若条件为假 则一直执行循环体
until CONDITION; do
循环体
done
Shell的函数
# 语法一
function FUNC_NAME {
函数体
return [N]
}
# 语法二
FUNC_NAME() {
函数体
return [N]
}
# return 返回自定义函数执行状态码,只能返回0-255之间的整数。
# 如果没有显式的指定返回状态码,则返回函数最后一条指令的状态码
# 函数的传参 `FUNC arg1 arg2…argN`
# 函数参数的调用 在函数内 `$1 $2… $@ $*`
Shell的数组
能够存储多个元素的连续的内存空间
# 定义数组
ARRAY=(arg1 arg2 … argN)
# 通过read创建数组
read -a ARRAY
# 打印整个数组
echo ${ARRAY[*]}
echo ${ARRAY[@]}
# 数组的赋值与修改
ARRAY[INDEX]=VALUE
# 查看数组长度
echo ${#ARRAY[*]}
# 数组的删除
unset ARRAY
unset ARRAY[INDEX]
# 数组的切片 N1为起始索引位置 N2为截取元素个数
# N2可省略 表示截取到最后一个元素
echo ${ARRAY[*]:N1:N2}
# 打印数组最后N个元素
echo ${ARRAY[*]: -N}
# 数组元素的替换 使用的是变量子串操作
echo ${ARRAY[*]/pat1/sub1}
Shell的变量子串操作
以下操作适用于字符串操作和数组操作。支持使用glob 如*,[],|
等
变量切片和长度获取
# `${#string}` 显示变量长度
echo ${#string}
# 变量的切片 N1为起始索引位置 N2为截取元素个数
# N2可省略 表示截取到最后一个元素
echo ${var:N1:N2}
# 取最后N个元素 `-N`前必须有空格
echo ${var: -N}
变量删除替换操作
# 测试字符串数据
[root@stardust tools]# test=abcABC123abcABC
# ${string#substring} 从string开头删除最短匹配字符串
# ${string##substring} 从string开头删除最长匹配字符串
[root@stardust tools]# echo ${test#a*c}
ABC123abcABC
[root@stardust tools]# echo ${test##a*c}
ABC
# ${string%substring} 从string结尾删除最短匹配字符串
# ${string%%substring} 从string结尾删除最长匹配字符串
[root@stardust tools]# echo ${test%a*C}
abcABC123
[root@stardust tools]# echo ${test%%a*C}
===========================================================================
# 测试字符串数据
[root@stardust tools]# test="root:x:0:0:root:/root:/bin/bash:root"
# ${parameter/pattern/string} 替换第一个匹配的字符串
[root@Stardust ~]# echo ${test/root/ROOT}
ROOT:x:0:0:root:/root:/bin/bash:root
# ${parameter//pattern/string} 替换所有匹配的字符串
[root@Stardust ~]# echo ${test//root/ROOT}
ROOT:x:0:0:ROOT:/ROOT:/bin/bash:ROOT
# ${parameter/#pattern/string} 行首锚定 匹配开头第一个字段
# ${parameter/%pattern/string} 行尾锚定 匹配结尾第一个字段
# 以上多种形式`/string`部分可以省略 表示替换为空,即删除
[root@Stardust ~]# echo ${test/root}
test::x:0:0:root:/root:/bin/bash:root
[root@Stardust ~]# echo ${test//root}
test::x:0:0::/:/bin/bash:
字符串大小写转换
# 把所有字母转换为大写
[root@Stardust ~]# echo ${var^^}
# 把所有字母转换为小写
[root@Stardust ~]# echo ${var,,}
变量子串赋值
# 如果变量为空或未设定, 返回default。存在则返回变量的值
echo ${var:-default}
# 如果变量为空或未设定, 给变量赋值默认值default
echo ${var:=default}
# 如果变量存在且非空则返回default。变量为空或未设定,不做任何操作。
echo ${var:+default}
# 如果变量为空或未设定, 返回错误信息
echo ${var:?error_info}
Shell的特殊关键字
shift(变量左移)
# `shift [N]` shift会将当前位置的变量销毁,并将后面位置的变量依次向前移动N位
# 变量移位测试代码
#!/bin/bash
while [ $# != 0 ]
do
echo "第一个参数为:$1,参数个数为:$#"
shift
done
# 执行结果 $1在不断变化 变量数量在不断减少
[root@stardust ~]# sh shift.sh a b c d e f g
第一个参数为:a,参数个数为:7
第一个参数为:b,参数个数为:6
第一个参数为:c,参数个数为:5
第一个参数为:d,参数个数为:4
第一个参数为:e,参数个数为:3
第一个参数为:f,参数个数为:2
第一个参数为:g,参数个数为:1
=======================================================================
# 变量移位测试代码
#!/bin/bash
echo "变量个数 $# 变量为 $*"
shift
echo "变量个数 $# 变量为 $*"
shift 2
echo "变量个数 $# 变量为 $*"
shift 3
echo "变量个数 $# 变量为 $*"
# 执行结果 第一次销毁1个变量 第二次销毁2个 第三次销毁3个
[root@stardust ~]# sh shift_test.sh a b c d e f g
变量个数 7 变量为 a b c d e f g
变量个数 6 变量为 b c d e f g
变量个数 4 变量为 d e f g
变量个数 1 变量为 g
read(命令行读入数据)
# `read`支持指定多个形参 接收多个实参
[root@stardust ~]# read arg1 arg2 arg3
# `-p 'PROMPT'` 指定提示信息
[root@stardust ~]# read -p "message:" arg1 arg2 arg3
# `-t TIMEOUT` 设定超时时间
[root@stardust ~]# read -t
sh(调用shell解释器)
[root@stardust ~]# sh -n # 检查语法错误 不能检查出逻辑错误
[root@stardust ~]# sh -x # 调试执行
exit(退出程序并返回状态码)
exit [N]
自定义退出状态码- 脚本中一旦遇到exit命令,脚本会立即终止。退出状态码取决于exit命令后面的数字
- 如果脚本未给定退出状态码,整个脚本的退出状态码取决于脚本中执行的最后一条命令的状态码
break(跳出循环)
break [N]
跳出循环[N]
代表层数,跳出N层循环
continue(执行下一次循环)
continue [N]
提前结束循环 继续执行下一次循环[N]
代表层数,提前结束N层循环,继续执行下一次循环
source(读取其他脚本内容)
使用source
或.
读取其他脚本内容,相当于python中的import
source /PATH/TO/FILE
. /PATH/TO/FILE