Shell 脚本速查表
本页面汇总了 Shell 脚本编程最常用的语法和命令,方便快速查阅。
脚本结构
#!/bin/bash
# Shebang:指定解释器
set -e # 命令失败时退出
set -u # 使用未定义变量时报错
set -x # 打印执行的命令
set -o pipefail # 管道中任何命令失败时返回失败
# 或合并写法
set -euo pipefail
变量
定义和使用
name="John" # 定义变量(等号两边不能有空格)
echo $name # 使用变量
echo ${name} # 推荐使用花括号
echo "${name}'s home" # 字符串中使用
readonly PI=3.14 # 只读变量
unset name # 删除变量
特殊变量
| 变量 | 含义 |
|---|---|
$0 | 脚本名称 |
$1-$9 | 第 1-9 个参数 |
${10} | 第 10 个及之后的参数 |
$# | 参数个数 |
$@ | 所有参数(独立字符串) |
$* | 所有参数(单个字符串) |
$? | 上一个命令的退出状态 |
$$ | 当前进程 PID |
$! | 最后一个后台进程 PID |
$RANDOM | 随机数 0-32767 |
$LINENO | 当前行号 |
$BASH_VERSION | Bash 版本 |
$FUNCNAME | 当前函数名 |
参数扩展
${var:-default} # var 未定义则使用 default
${var:=default} # var 未定义则赋值并使用
${var:+alternative} # var 已定义则使用 alternative
${var:?error} # var 未定义则打印错误并退出
${#var} # 字符串长度
${var:start:length} # 子字符串
${var#pattern} # 删除最短前缀匹配
${var##pattern} # 删除最长前缀匹配
${var%pattern} # 删除最短后缀匹配
${var%%pattern} # 删除最长后缀匹配
${var/old/new} # 替换第一个匹配
${var//old/new} # 替换所有匹配
${var^} # 首字母大写
${var^^} # 全部大写
${var,} # 首字母小写
${var,,} # 全部小写
数组
索引数组
arr=(a b c d) # 创建数组
arr[4]=e # 添加元素
arr+=(f g) # 追加元素
echo ${arr[0]} # 访问元素
echo ${arr[@]} # 所有元素
echo ${#arr[@]} # 数组长度
echo ${!arr[@]} # 所有索引
unset arr[1] # 删除元素
unset arr # 删除数组
关联数组
declare -A dict
dict=([name]="John" [age]=25)
echo ${dict[name]} # 访问元素
echo ${!dict[@]} # 所有键
echo ${dict[@]} # 所有值
遍历数组
# 遍历元素
for item in "${arr[@]}"; do
echo "$item"
done
# 遍历索引
for i in "${!arr[@]}"; do
echo "$i: ${arr[$i]}"
done
字符串
str="Hello, World!"
# 长度
${#str} # 13
# 子字符串
${str:0:5} # Hello
${str:7} # World!
${str: -6} # World!(注意空格)
# 替换
${str/World/Shell} # Hello, Shell!
${str//o/0} # Hell0, W0rld!
# 大小写
${str^^} # HELLO, WORLD!
${str,,} # hello, world!
# 删除前后缀
path="/usr/local/bin/script.sh"
${path##*/} # script.sh(文件名)
${path%/*} # /usr/local/bin(目录名)
条件判断
文件测试
| 运算符 | 含义 |
|---|---|
-e | 存在 |
-f | 是普通文件 |
-d | 是目录 |
-r | 可读 |
-w | 可写 |
-x | 可执行 |
-s | 非空 |
-L | 是符号链接 |
-nt | 比另一个新 |
-ot | 比另一个旧 |
数值比较
| 运算符 | 含义 |
|---|---|
-eq | 等于 |
-ne | 不等于 |
-gt | 大于 |
-ge | 大于等于 |
-lt | 小于 |
-le | 小于等于 |
字符串比较
| 运算符 | 含义 |
|---|---|
= | 相等 |
!= | 不相等 |
-z | 长度为 0 |
-n | 长度不为 0 |
条件语法
# if 语句
if [[ condition ]]; then
commands
elif [[ condition ]]; then
commands
else
commands
fi
# [ ] 和 [[ ]] 和 (())
[ "$a" -eq "$b" ] # 基本测试
[[ $a -eq $b ]] # 扩展测试(推荐)
(( a == b )) # 算术测试
# 逻辑运算
[[ -f "$f" && -r "$f" ]] # 与
[[ -f "$f" || -d "$f" ]] # 或
[[ ! -f "$f" ]] # 非
# 正则匹配
[[ "$str" =~ ^[0-9]+$ ]] # 匹配纯数字
循环
for 循环
# 遍历列表
for item in a b c; do
echo $item
done
# 遍历范围
for i in {1..5}; do
echo $i
done
# C 风格
for ((i=0; i<5; i++)); do
echo $i
done
# 遍历数组
for item in "${arr[@]}"; do
echo $item
done
# 遍历文件
for file in *.txt; do
echo "$file"
done
while 循环
while [[ condition ]]; do
commands
done
# 读取文件
while IFS= read -r line; do
echo "$line"
done < file.txt
# 无限循环
while true; do
commands
done
until 循环
until [[ condition ]]; do
commands
done
循环控制
break # 跳出循环
break 2 # 跳出 2 层循环
continue # 跳过当前迭代
case 语句
case $var in
pattern1)
commands
;;
pattern2|pattern3)
commands
;;
[a-z])
echo "小写字母"
;;
*)
default commands
;;
esac
函数
# 定义函数
func() {
local var="local" # 局部变量
echo "Hello, $1!"
return 0 # 返回状态码
}
# 调用
func "World"
# 获取返回值
result=$(func "World") # 捕获输出
status=$? # 获取退出状态
输入输出
重定向
cmd > file # 输出到文件(覆盖)
cmd >> file # 输出到文件(追加)
cmd 2> file # 错误输出到文件
cmd &> file # 所有输出到文件
cmd < file # 从文件输入
cmd1 | cmd2 # 管道
cmd <<< "string" # Here String
Here Document
cat << EOF
Line 1
Line 2
$variable # 会展开
EOF
cat << 'EOF'
$variable # 不会展开
EOF
读取输入
read var # 读取一行
read -p "Prompt: " var # 带提示
read -s var # 静默输入(密码)
read -t 5 var # 5 秒超时
read -a arr # 读取到数组
IFS=',' read -a arr # 指定分隔符
算术运算
# 算术扩展
$((a + b)) # 加
$((a - b)) # 减
$((a * b)) # 乘
$((a / b)) # 除
$((a % b)) # 取模
$((a ** b)) # 幂
# 自增/自减
((i++))
((i--))
# 复合赋值
((i += 5))
# 比较运算符
((a == b)) # 等于
((a != b)) # 不等于
((a > b)) # 大于
((a < b)) # 小于
# 位运算
((a & b)) # 按位与
((a | b)) # 按位或
((a ^ b)) # 按位异或
((a << n)) # 左移
((a >> n)) # 右移
命令行参数解析
位置参数
$0 # 脚本名称
$1, $2, ... # 位置参数
$# # 参数个数
$@ # 所有参数(独立)
$* # 所有参数(合并)
shift # 参数左移
shift 2 # 左移 2 位
getopts
while getopts "a:b:c" opt; do
case $opt in
a) arg_a="$OPTARG" ;;
b) arg_b="$OPTARG" ;;
c) flag_c=1 ;;
\?) echo "无效选项: -$OPTARG" >&2; exit 1 ;;
:) echo "选项 -$OPTARG 需要参数" >&2; exit 1 ;;
esac
done
shift $((OPTIND-1))
变量说明
| 变量 | 含义 |
|---|---|
OPTIND | 下一个参数索引 |
OPTARG | 当前选项的参数值 |
OPTERR | 是否显示错误(0 禁用) |
长选项(手动解析)
while [[ $# -gt 0 ]]; do
case $1 in
-f|--file)
file="$2"
shift 2
;;
-v|--verbose)
verbose=1
shift
;;
--)
shift
break
;;
*)
echo "未知选项: $1"
exit 1
;;
esac
done
文本处理
grep
grep "pattern" file # 搜索
grep -i "pattern" file # 忽略大小写
grep -v "pattern" file # 反向匹配
grep -r "pattern" dir # 递归搜索
grep -n "pattern" file # 显示行号
grep -c "pattern" file # 统计匹配数
grep -l "pattern" *.txt # 只显示文件名
grep -E "regex" file # 扩展正则
grep -o "pattern" file # 只显示匹配部分
grep -A 3 "pattern" file # 显示匹配行及后 3 行
grep -B 3 "pattern" file # 显示匹配行及前 3 行
grep -C 3 "pattern" file # 显示匹配行及前后各 3 行
sed
sed 's/old/new/' file # 替换第一个
sed 's/old/new/g' file # 替换所有
sed -i 's/old/new/g' file # 直接修改文件
sed '3d' file # 删除第 3 行
sed '/pattern/d' file # 删除匹配行
sed -n '5,10p' file # 打印第 5-10 行
sed 's/^/prefix: /' file # 行首添加
sed 's/$/ :suffix/' file # 行尾添加
awk
awk '{print $1}' file # 打印第 1 列
awk -F: '{print $1}' file # 指定分隔符
awk '$3 > 100' file # 条件过滤
awk '{sum+=$1} END{print sum}' # 求和
awk 'NR==5' file # 打印第 5 行
awk 'END{print NR}' file # 统计行数
awk '{print NR, $0}' file # 带行号输出
awk '{count[$1]++} END{for(k in count) print k, count[k]}' file # 统计频率
cut
cut -d: -f1 file # 按 : 分隔取第 1 列
cut -c1-5 file # 取第 1-5 个字符
cut -f2- file # 取第 2 列及之后
sort
sort file # 排序
sort -n file # 数值排序
sort -r file # 逆序
sort -u file # 去重排序
sort -t: -k3 file # 按第 3 列排序
sort -k1,1 -k2,2n file # 多列排序
uniq
sort file | uniq # 去重
sort file | uniq -c # 统计出现次数
sort file | uniq -d # 只显示重复行
sort file | uniq -u # 只显示不重复行
tr
tr 'a-z' 'A-Z' < file # 小写转大写
tr -d '0-9' < file # 删除数字
tr -s ' ' < file # 压缩空格
tr -d -c 'a-zA-Z' < file # 只保留字母
wc
wc -l file # 统计行数
wc -w file # 统计单词数
wc -c file # 统计字节数
wc -m file # 统计字符数
信号处理
# trap 语法
trap 'commands' signals
# 常用示例
trap 'echo "Interrupted"; exit' INT
trap 'cleanup; exit' EXIT
trap '' INT # 忽略信号
trap - INT # 恢复默认行为
常见信号
| 信号 | 编号 | 含义 | 触发方式 |
|---|---|---|---|
| SIGHUP | 1 | 挂起 | 终端关闭 |
| SIGINT | 2 | 中断 | Ctrl+C |
| SIGQUIT | 3 | 退出 | Ctrl+\ |
| SIGKILL | 9 | 强制终止 | kill -9 |
| SIGTERM | 15 | 终止 | kill |
| SIGUSR1 | 10 | 用户定义 | kill -USR1 |
| SIGUSR2 | 12 | 用户定义 | kill -USR2 |
后台任务
cmd & # 后台运行
nohup cmd & # 退出终端后继续运行
jobs # 查看后台任务
fg %1 # 调到前台
bg %1 # 放到后台
wait # 等待所有后台任务
wait $pid # 等待指定进程
wait -n # 等待任意一个完成
disown %1 # 从任务列表移除
进程管理
ps aux # 查看进程
pstree # 查看进程树
pgrep name # 查找进程 PID
kill PID # 终止进程
kill -9 PID # 强制终止
killall name # 按名称终止
pkill pattern # 按模式终止
nice -n 10 cmd # 以较低优先级运行
renice -n 5 -p PID # 修改优先级
调试
bash -n script.sh # 检查语法
bash -x script.sh # 打印执行的命令
bash -v script.sh # 打印读取的行
# 脚本内
set -x # 开启调试
set +x # 关闭调试
set -e # 遇错退出
set -u # 未定义变量报错
# 使用 trap 调试
trap 'echo "Line $LINENO: $BASH_COMMAND"' DEBUG
安全检查清单
变量处理
- 所有变量都用双引号包围:
"$var" - 使用
set -u捕获未定义变量 - 避免使用
eval - 使用
local声明局部变量
输入验证
- 验证用户输入(白名单优于黑名单)
- 限制输入长度
- 验证文件路径,防止路径遍历
- 检查危险字符:
; | & $ \( ) < >`
文件操作
- 使用
mktemp创建临时文件 - 设置安全权限:
chmod 600 - 使用
trap清理临时文件 - 验证文件路径在允许范围内
敏感数据
- 不硬编码密码
- 使用环境变量或配置文件
- 日志中过滤敏感信息
- 使用后清理敏感变量
快捷键
| 快捷键 | 功能 |
|---|---|
Tab | 自动补全 |
Ctrl+C | 终止命令 |
Ctrl+D | 退出 Shell |
Ctrl+L | 清屏 |
Ctrl+A | 光标移到行首 |
Ctrl+E | 光标移到行尾 |
Ctrl+U | 删除光标前内容 |
Ctrl+K | 删除光标后内容 |
Ctrl+R | 搜索历史 |
Ctrl+Z | 暂停任务 |
Ctrl+W | 删除前一个单词 |
通配符
| 符号 | 含义 |
|---|---|
* | 匹配任意字符 |
? | 匹配单个字符 |
[abc] | 匹配 a、b、c |
[a-z] | 匹配范围 |
[!abc] | 不匹配 |
{a,b} | 匹配 a 或 b |
花括号扩展
{a,b,c} # a b c
{1..5} # 1 2 3 4 5
{a..e} # a b c d e
{1..10..2} # 1 3 5 7 9
file{,.bak} # file file.bak
dir_{a,b}/file # dir_a/file dir_b/file
常用命令
文件操作
ls -la # 列出文件
cp source dest # 复制
mv source dest # 移动/重命名
rm file # 删除文件
rm -rf dir # 删除目录
mkdir -p dir # 创建目录
touch file # 创建空文件
ln -s target link # 创建符号链接
find . -name "*.txt" # 查找文件
文件查看
cat file # 显示内容
less file # 分页查看
head -n 20 file # 前 20 行
tail -n 20 file # 后 20 行
tail -f file # 实时追踪
wc -l file # 统计行数
网络工具
ping host # 测试连通
curl url # 请求 URL
wget url # 下载文件
ssh user@host # SSH 连接
scp file user@host:path # 复制文件