基本语法
-
命令组合
;: 上一个命令不管执行失败还是成功都会执行下一个命令&&: 上一个命令执行成功,执行下一个命令||: 上一个命令执行失败,执行下一个命令
-
基本命令:
echo: 标准输出type: 查看命令类型shopt: 调整命令状态
dotglob: 使扩展命令包含隐藏文件
failglob: 不匹配直接报错
nullgolb: 不匹配返回空
-
快捷键:
ctrl + l: 清屏ctrl + u: 清除到行首ctrl + k: 清除到行尾ctrl + w: 删除一个域ctrl + a: 跳转到行首ctrl + e: 跳转到行尾
-
扩展:
?: 任意单字符*: 任意多字符[]: 匹配括号内的字符{}: 遍历括号里面的所有值,值用逗号连接,不能有空格$: 变成变量
${!variable}: 间接引用,获得变量的变量值
${!string*}: 扩展指定前缀变量
$(...): 扩展另一命令结果
$((...)): 算术结果[[:class:]]: 字符类
-
量词语法:
?: 匹配零次或一次*: 匹配零次或多次+: 匹配一次或多次@: 只匹配一次!: 否判断
-
单引号:保留字符的基本含义。
如果需要转义,需要双重转义,$'\'',或者使用"'" -
双引号:大部分特殊字符都会失去原含义。
除了:
$: 引用变量
`: 执行子命令
\: 转义 -
Here 文档:
<< token token -
Here 字符串:
<<< string
变量
-
定义变量:
variable=value -
读取变量:
$variableor${variable}, 放在双引号里读取保留原有格式。 -
删除变量:
unset variableorvariable=''orvariable= -
输出变量:
export variable -
特殊变量:
$?: 上一个命令的退出码
$$: 当前 shell 的进程 ID
$_: 上一个命令的最后一个参数
$!: 最后一个后台执行的异步命令 id
$0: 当前 shell 的名称
$-: 当前 shell 的启动参数
$@: 脚本参数数量$#: 脚本参数值 -
变量默认值
${var:-word}: 返回变量值(存在不为空)或者 word
${var:=word}: 返回变量值(存在不为空),否则把 word 赋给变量并返回${var:+word}: 变量存在不为空,则返回 word,否则返回空${var:?word}: 返回变量值(存在不为空)或者var:word -
声明特殊变量:
declare OPTION VARIABLE=valuereadonly OPTION VARIABLE=valuelet
字符串操作
-
获取字符串长度:
${#var} -
提取子字符串:
${var:offset:length} -
字符串头部匹配:
${var#pattern}: 非贪婪
${var##pattern: 贪婪 -
字符串尾部匹配:
${var%pattern: 非贪婪
${var%%pattern: 贪婪 -
字符串任意位置匹配:
${var/pattern}: 非贪婪
${var//pattern}: 贪婪 -
替换:
${var#pattern/string}
${var%pattern/string}
${var/pattern/string} -
改变大小写
${var^^}: 转大写
${var,,}: 转小写
运算(待施工)
行操作(待施工)
目录堆栈(待施工)
脚本基础
-
执行一个环境变量中的命令:
/usr/bin/env NAME -
注释:
# -
脚本特殊变量:
$0: 脚本文件名
$1-9: 脚本参数
$#: 参数总和
$@: 全部参数,空格分隔$*: 全部参数,使用$IFS值第一个字符分隔 -
-n: 变量为空 -
-d: 变量为目录 -
shift: 移除脚本第一个参数 -
getopts: 解析复杂的脚本命令行参数 -
--: 配置项参数终止符 -
exit: 退出命令 -
source: 执行命令,通常重新加载配置,不新建 shell -
alias: 别名
标准输入
read [-options] [variable...]: 读取输入IFS=":" read [-options] [variable...]: 修改分隔标志<<<: 将变量转化为标准输入<: 定向符,将文件内容导入 read,每次读取一行
条件判断
-
if 结构:
if commands; then commands [elif commands; then commands...] [else commands] fi -
test 命令:
test expressionor[expression]or[[expression]] -
常用 test 命令:
-
文件
[ -a file ]: file 存在[ -b file ]: file 存在且为块文件[ -c file ]: file 存在且为字符文件[ -d file ]: file 存在且为目录[ -e file ]: file 存在[ -f file ]: file 存在且为普通文件[ -g file ]: file 设置了组 id[ -G file ]: file 设置了有效组 ID[ -h file ]: file 为符号链接[ -k file ]: file 设置了 sticky bit[ -L file ]: file 设置了是软链接[ -N file ]: 上次读取后已修改[ -O file ]: 属于有效用户 id[ -p file ]: 是一个命名管道[ -r file ]: 存在且可读[ -w file ]: 存在且可写[ -x file ]: 存在且可执行[ -s file ]: 存在长度大于 0[ -S file ]: 是一个 socket[ file1 -nt file2 ]: file1 比 file2 更新,或 file1 存在 file2 不存在[ file1 -ot file2 ]: file1 比 file2 更旧,或 file1 不存在 file2 存在
-
字符串
-
[ string ]: 不为空 -
[ -n string ]: string 长度大于 0 -
[ -z string ]: string 长度为 0 -
[ string1 = string2 ]: string1 和 string2 相同 -
[ string1 == string2 ]: 同上 -
[ string1 != string2 ]: 不相同 -
[ string1 '>' string2 ]: string1 字典顺序在 string2 之后 -
[ string1 '<' string2 ]: string1 在 string2 前字符串判断时,变量要放到双引号中。
-
-
整数
[ integer1 -eq integer2 ]: =[ integer1 -ne integer2 ]: !=[ integer1 -le integer2 ]: <=[ integer1 -lt integer2 ]: <[ integer1 -ge integer2 ]: >=[ integer1 -gt integer2 ]: >
-
正则
[[ string1 =~ regex ]]
-
逻辑运算
&& or || or !
-
算术运算
((3 > 2))
-
-
case 结构
case expression in pattern ) command ;; pattern ) command ;; ... esac
循环
-
while 循环
while condition; do command done -
util 循环
until condition; do command done -
for 循环
for variable in list; do command donefor (( expression1; expression2; expression3 )); do command done # expression1 初始化条件 # expression2 判断条件 # expression3 更新值 -
break: 跳出循环 -
continue: 进入下一轮循环 -
select 结构(一般和 case 联动)
select name [in list] do command done
函数
-
定义:
func() { command return }或者
function func() { command return } -
删除函数:
unset -f FuncName -
查看所有的函数:
declare -f -
查看函数定义:
declare -f FuncName -
参数:
$1-$9: 第 1-9 个参数$0: 脚本名$#: 参数总和$@: 全部参数,空格分隔$*: 全部参数,$IFS第一个字符分隔
-
函数内的变量是全局变量,如果要声明局部变量需要使用
local
数组
-
创建数组
ARRAY[INDEX]=valueARRAY=(val1 val2 val3)ARRAY=([0]=val2 [2]=val1 [1]=val3)ARRAY=( *.mp3 )使用通配符declare -a ARRAYread -a ARRAY
-
读取数组
${array[i]}${array[@]}or${array[*]}读取所有成员:“aa bb” 会被读取成 aa bb 两个成员"${array[@]}"读取所有成员:“aa bb”会被读取成一个成员"${array[*]}"所有成员会被变成一个单字符串读取- 如果没有指定成员,默认使用 0 号成员
- 读取数组长度:
${#array[*]}or${#array[@]} - 读取所有成员索引:
${!array[@]}or${!array[*]}
-
切片:
${array[@]:position:length} -
追加成员:
array+=(val) -
删除数组:
unset array[idx]unset array:删除整个数组
-
关联数组(类似字典)
declare -A array
脚本环境
-
setset -uorset -o nounset:不忽略不存在的变量set -xorset -o xtrace:输出结果先输出命令set -eorset -o errexit:失败即退出set -eo pipfail:管道命令失败即退出set -E:修正没有被 trap 捕获的命令(设置了set -e)set -norset -o noexec:不运行,检查语法正确set -forset -o noglob:不对通配符进行文件名扩展set -vorset -o verbose:打印接受的输入set -o noclobber:防止重定向运算符>覆盖已存在文件。
-
报错退出(三种写法)
-
command || { echo "command failed"; exit 1; } -
if ! command; then echo "command failed"; exit 1; fi -
command; if [ "$?" -ne 0 ]; then echo "command failed"; exit 1; fi
-
-
忽略某行失败不退出(设置了
set -e)- 使用
set +eset +e command set -e - 使用
command || true
- 使用
-
shoptshopt -s:开启参数shopt -u:关闭参数shoptorshopt -q:查询参数状态
脚本除错
-
考虑命令失败的情况,特别是删除等操作,一定要确保文件存在。
-
$LINENO:脚本中的行号 -
$FUNCNAME:返回本函数和引用者名称的数组 -
$BASH_SOURCE:返回本脚本和调用者名称的数组 -
$BASH_LINENO:返回每一轮调用的行号 -
临时文件创建原则:
- 检查文件是否已存在
- 确保文件创建成功
- 权限限制
- 使用不可预测文件名
- 脚本退出时要清理临时文件
-
mktemp:-d:创建临时目录-p:指定路径,默认/tmp-t:指定模板
-
trap command signal:响应系统信号HUP:编号 1,脚本与所在终端脱离联系INT:编号 2,Ctrl+C,终止脚本运行QUIT:编号 3,Ctrl+a,退出脚本KILL:编号 9,杀死进程TERM:编号 15,kill 默认信号EXIT:bash 脚本特有信号,退出产生
启动环境
-
登录 session
-
脚本环境初始化顺序:
/etc/profile/etc/profile.d~/.bash_profile~/.bash_login~/.profile
其中 bash_profile、bash_login 若执行后就不往后执行了,没有的情况下往后执行
-
bash --login:强制执行登录 session 的脚本 -
bash --noprofile:会跳过上面的 profile 脚本
-
-
非登录 session
-
脚本环境初始化顺序:
/etc/bash.bashrc/.bashrc
-
bash --norc:禁止调用.bashrc 脚本 -
bash --rcfile filename:指定 bashrc 脚本 -
~/.bash_logout:退出时的清理工作
-
-
bash参数-n:不执行脚本,只检查语法错误-v:输出执行语句-x:输出执行命令
-
~/.inputrc:键盘绑定
参考链接
- Bash 脚本教程, 阮一峰