Shell
语法速记
在文件第一行可声明脚本解释器:#!/bin/bash 或 #!/bin/sh。
注释:
# 以 `#` 开头的行就是注释,会被解释器忽略
:<<EOF
也可以用分界符做多行注释
其中,`:` 是空语句,表示什么都不做
EOF
变量:
# 变量名只能使用字母,数字和下划线,首个字符不能以数字开头
# 当变量值不包含空白符时,可以不使用引号包围起来
variable=this_is_a_string
# 当以单引号' '包围变量值时,不会解析里面的变量和命令
variable='this is a string'
# 当以双引号" "包围变量的值时,会解析里面的变量和命令
variable="this is a string"
# 使用一个定义过的变量,只要在变量名前面加美元符号即可
echo $variable
# 使用变量时,在变量名外加上花括号{ },可以帮助解释器识别变量的边界
echo "variable: ${variable}Value"
# 变量 variable 值为 null 时,输出 default
echo "${variable-default}"
# 变量 variable 值为 null 时,赋值 default 并输出
echo "${variable=default}"
# 变量 variable 值为 null 或空字符串时,输出 default
echo "${variable:-default}"
# 变量 variable 值为 null 或空字符串时,赋值 default 并输出
echo "${variable:=default}"
# 变量 variable 值非空时,输出 default
echo "${variable:+default}"
# 变量 variable 值为 null 或空字符串时,报错 default 并退出
echo "${variable:?default}"
# 定义数组
variable=()
variable=(value1 value2 ...)
variable=([0]=value1 [1]=value2 ...)
# 修改数组
variable[index]=value
# 获取数组中的指定成员
echo "${variable[index]}"
# 获取数组中所有成员,所有成员被看做一个整体
echo "${variable[*]}"
# 获取数组中所有成员,成员间仍是相互独立的
echo "${variable[@]}"
# 支持将命令执行的输出结果赋值给变量
variable=`command`
variable=$(command)
# 使用 readonly 命令可以将变量定义为只读变量,只读变量的值不能被改变
readonly variable
# 使用 unset 命令可以删除变量,unset 命令不能删除只读变量
unset variable
# Shell 变量有三种作用域:
# * 局部变量:在函数内部生效
# * 全局变量:在当前 Shell 进程中生效
# * 环境变量:在当前 Shell 进程及其子进程中生效
# 在 Shell 中定义的变量,默认就是全局变量
# 定义局部变量
local variable="this is a string"
# 定义环境变量
export variable
export variable="this is a string"
# 在 Bash 中,变量值都是以字符串的形式存储,默认情况下不会区分变量类型
# 使用 declare 关键字可以显式定义变量的类型属性:`-` 赋予属性,`+` 删除属性
# 列出用户定义的函数名称和函数体
declare -f [function]
# 列出用户定义的函数名称
declare -F [variable]
# 显示指定变量的属性和值
declare -p [variable]
# 当在函数中,declare 默认声明局部变量,可使用 `-g` 选项设置全局变量
declare -g variable[=value]
# 声明变量为整数,此时会对变量值做算术运算,类似 let 命令
declare -i variable[=value]
# 声明变量为小写,此时会对变量值做小写字母转换
declare -l variable[=value]
# 声明变量为大写,此时会对变量值做大写字母转换
declare -u variable[=value]
# 声明变量为只读,等价于 readonly name
declare -r variable[=value]
# 声明变量为环境变量,等价于 export name[=value]
declare -x variable[=value]
# 声明变量为普通数组
declare -a variable
declare -a variable=(value1 value2 ...)
declare -a variable[index]=value
# 声明变量为关联数组(支持索引下标为字符串)
declare -A variable
declare -A variable=([key1]=value1 [key2]=value2 ...)
declare -A variable[key]=value
特殊变量:
# bash 解析器执行脚本的文件名
$0
# 传递给脚本或函数的参数,n 是数字,表示参数位置
$1 $2 $3 ... $n
# 传递给脚本或函数的参数个数
$#
# 传递给脚本或函数的所有参数。当被双引号" "包含时,会将所有的参数看做一个整体
$*
# 传递给脚本或函数的所有参数。当被双引号" "包含时,参数间仍是相互独立的
$@
# 上个命令的退出状态,或函数的返回值
$?
# 当前 Shell 进程 ID
$$
# 后台运行的最后一个进程 ID
$!
# 显示当前 Bash 使用的选项,与 set 命令功能相同
$-
字符串:
# 变量 variable 赋值多行字符串
variable="
this is line 1
this is line 2
"
# 变量 variable 赋值多行字符串,cat + EOF 块组合
variable=$(cat <<- EOF
this is line 1
this is line 2
EOF
)
# 变量 variable 赋值多行字符串,read 命令会去除字符串前后的空白字符
read -r -d '' variable <<- EOF
this is line 1
this is line 2
EOF
# 获取字符串长度
echo ${#variable}
# 字符串拼接
variable=${string1}${string2}
variable=${string1}" string2 "${string3}
variable="${string1} string2 ${string3} string4"
# 字符串替换,将匹配的第一个 oldstring 替换成 newstring
echo "${variable/oldstring/newstring}"
# 字符串替换,将所有匹配的 oldstring 替换成 newstring
echo "${variable//oldstring/newstring}"
# 指定位置截取字符串:从左边位置 start 开始向右截取长度 length,start 从 0 开始计数,省略 length,截取到字符串末尾
echo "${variable:start:length}"
echo "${variable:start}"
# 指定位置截取字符串:从右边位置 start 开始向右截取长度 length,start 从 1 开始计数,省略 length,截取到字符串末尾
echo "${variable:0-start:length}"
echo "${variable:0-start}"
# 从指定子串开始截取:从左边计算,第一次出现 *string 的位置开始,截取 *string 右边的所有字符
echo "${variable#*string}"
# 从指定子串开始截取:从左边计算,最后一次出现 *string 的位置开始,截取 *string 右边的所有字符
echo "${variable##*string}"
# 从指定子串开始截取:从右边计算,第一次出现 string* 的位置开始,截取 *string 左边的所有字符
echo "${variable%string*}"
# 从指定子串开始截取:从右边计算,最后一次出现 string* 的位置开始,截取 *string 左边的所有字符
echo "${variable%%string*}"
数组:
# Bash 依据变量 IFS 来拆解字符串(会影响到字符串分割数组,循环遍历等),IFS 默认值为 $' \t\n'
# 获取数组的元素个数
echo "${#array[@]}"
echo "${#array[*]}"
# 获取数组元素的长度
echo "${#array[index]}"
# 获取数组所有的键
echo "${!array[@]}"
echo "${!array[*]}"
# 数组拼接
array=(${array1[@]} ${array2[@]})
array=(${array1[*]} ${array2[*]})
# 删除指定的数组元素
unset variable[index]
# 关联数组使用字符串作为下标,其元素是无序的。它在使用上和普通数组一样
# Bash 默认使用普通数组,在使用关联数组前,必须要先定义它
declare -A array=()
# 遍历数组:for
for ((i=0;i<${#array[@]};i++)); do
echo "${array[i]}"
done
# 遍历数组:for .. in,建议用 ${array[@]},防止因空白符导致的异常
for value in "${array[@]}"; do
echo "$value"
done
# 遍历数组下标:for .. in,适合遍历关联数组
for key in "${!array[@]}"; do
echo "${array[$key]}"
done
# 遍历数组:while
i=0
while [ $i -lt ${#array[@]} ]; do
echo "${array[$i]}"
let i++
done
算术运算:
# (( expression )),只能进行整数运算,会自动解析变量名
((a=10+66,b=a-15,c=a+b))
((a>7 && b==c))
echo $((a+10))
# let expression,只能进行整数运算
let a+=6 c=a+b
let 'a+=6 c=a+b'
let "a+=6 c=a+b"
# $[ expression ],只能进行整数运算
m=$[n*2]
echo $[m+n]
echo $[$m*$n]
echo $[4*(m+n)]
# expr expression,进行整数运算
expr 2 + 3
expr \( 2 + 3 \) \* 4
expr $m \* \( $n + 5 \)
# echo "expression" | bc,进行科学运算
# scale 设置小数位,ibase 设置输入数字的进制,obase 设置输出数字的进制
echo "15+5" | bc
echo 'scale=2; (2.777 - 1.4744)/1' | bc
echo "ibase=2;111" |bc
echo "obase=2;172" | bc
echo "sqrt(99)" | bc
# declare -i var=expression,进行整数运算
declare -i var=1+2
流程控制:
# test 命令用来检测某个条件是否成立,它可以简写为 []
# 常见用法如下:
# 判断文件是否存在,并且是否为块设备文件
[ -b "$filename" ]
# 判断文件是否存在,并且是否为字符设备文件
[ -c "$filename" ]
# 判断文件是否存在,并且是否为目录文件
[ -d "$filename" ]
# 判断文件是否存在
[ -e "$filename" ]
# 判断文件是否存在,井且是否为普通文件
[ -f "$filename" ]
# 判断文件是否存在,并且是否为符号链接文件
[ -L "$filename" ]
# 判断文件是否存在,并且是否为管道文件
[ -p "$filename" ]
# 判断文件是否存在,并且是否为非空
[ -s "$filename" ]
# 判断该文件是否存在,并且是否为套接字文件
[ -S "$filename" ]
# 判断文件是否存在,并且是否拥有读权限
[ -r "$filename" ]
# 判断文件是否存在,并且是否拥有写权限
[ -w "$filename" ]
# 判断文件是否存在,并且是否拥有执行权限
[ -x "$filename" ]
# 判断文件是否存在,并且是否拥有 SUID 权限
[ -u "$filename" ]
# 判断文件是否存在,并且是否拥有 SGID 权限
[ -g "$filename" ]
# 判断该文件是否存在,并且是否拥有 SBIT 权限
[ -k "$filename" ]
# 判断 filename1 的修改时间是否比 filename2 的新
[ "$filename1" -nt "$filename2" ]
# 判断 filename1 的修改时间是否比 filename2 的旧
[ "$filename1" -ot "$filename2" ]
# 判断 filename1 是否和 filename2 的 inode 号一致,可以理解为两个文件是否为同一个文件
[ "$filename1" -ef "$filename2" ]
# 判断 num1 是否和 num2 相等
[ "$num1" -eq "$num2" ]
# 判断 num1 是否和 num2 不相等
[ "$num1" -ne "$num2" ]
# 判断 num1 是否大于 num2
[ "$num1" -gt "$num2" ]
# 判断 num1 是否小于 num2
[ "$num1" -lt "$num2" ]
# 判断 num1 是否大于等于 num2
[ "$num1" -ge "$num2" ]
# 判断 num1 是否小于等于 num2
[ "$num1" -le "$num2" ]
# 判断字符串 str 是否为空
[ -z "$str" ]
# 判断宇符串 str 是否为非空
[ -n "$str" ]
# 判断 str1 是否和 str2 相等,= 和 == 是等价的
[ "$str1" = "$str2" ]
[ "$str1" == "$str2" ]
# 判断 str1 是否和 str2 不相等
[ "$str1" != "$str2" ]
# 判断 str1 是否大于 str2
[ "$str1" \> "$str2" ]
# 判断 str1 是否小于 str2
[ "$str1" \< "$str2" ]
# 逻辑与,表达式 expression1 和 expression2 都成立,最终的结果才是成立的
[ expression1 -a expression ]
# 逻辑或,表达式 expression1 和 expression2 有一个成立,最终的结果就成立
[ expression1 -o expression2 ]
# 逻辑非,对 expression 进行取反
[ !expression ]
# [[ expression ]] 是 test 的升级版
# 有以下优化:
# 不需要把变量名用双引号""包围起来,即使变量是空值,也不会出错
# 不需要、也不能对 >、< 进行转义,转义后会出错
# 支持逻辑运算符:[[ -z $str1 || -z $str2 ]],[[ -z $str1 && -z $str2 ]]
# 支持正则表达:[[ str =~ regex ]]
# if 条件判断
if condition1
then
statement1
elif condition2
then
statement2
elif condition3
then
statement3
else
statementn
fi
# case 条件判断
case expression in
pattern1)
statement1
;;
pattern2)
statement2
;;
pattern3)
statement3
;;
*)
statementn
esac
# while 循环
while condition
do
statements
done
# until 循环
until condition
do
statements
done
# for 循环
for ((exp1; exp2; exp3))
do
statements
done
# for in 循环
for variable in value_list
do
statements
done
# select in 循环
# select 是死循环,执行后以菜单的形式打印 value_list,然后根据菜单编号设置 variable,执行 statements
select variable in value_list
do
statements
done
# continue,跳过当前循环
# break,跳过整个循环
函数:
name()
{
statements
[return value]
}
function name
{
statements
[return value]
}
function name()
{
statements
[return value]
}

浙公网安备 33010602011771号