Bash 命令速查表 - Shell 脚本编程常用语法大全
写脚本最容易踩的坑是空白文件名没加引号、变量为空时读了未定义值、以及忘记 set -euo pipefail。这张表把变量扩张、判断、循环、函数这些高频语法收纳,按"写出来就不容易翻车"的标准组织,照抄即可用。
典型使用场景
在服务器上写脚本、处理文本与日志、批量重命名与查找文件、管道组合命令,以及排查脚本权限、变量未导出、通配符未展开等常见问题。
变量 Variables 8
NAME="value"echo $NAMEecho ${NAME}readonly NAME="value"unset NAME${VAR:-default}${VAR:=default}${#VAR}条件判断 Conditionals 7
if [ condition ]; then ... fiif [ -f file ]; then ... fiif [ $a -eq $b ]; then ... fiif [ "$str" = "value" ]; then ... fiif [[ $str =~ regex ]]; then ... fi[ -d dir ] && echo "exists"case $var in pattern1) ... ;; pattern2) ... ;; esac循环 Loops 6
for i in 1 2 3; do echo $i; donefor ((i=0; i<10; i++)); do ... donewhile [ condition ]; do ... doneuntil [ condition ]; do ... donebreak / continueselect var in list; do ... done函数 Functions 7
function name() { ... }name() { ... }name arg1 arg2$1 $2 $@$#return 0local var="value"字符串操作 String Operations 7
${VAR:offset:length}${VAR#pattern}${VAR##pattern}${VAR%pattern}${VAR%%pattern}${VAR/pattern/replacement}${VAR//pattern/replacement}文件测试 File Tests 8
[ -f file ][ -d dir ][ -e path ][ -r file ][ -w file ][ -x file ][ -s file ][ file1 -nt file2 ]高频补充命令(容量增强 · REQ-02) 36
${VAR:-default}${VAR:=default}${VAR:?error}${VAR#prefix}${VAR##prefix}${VAR%suffix}${VAR%%suffix}${VAR:0:5}${#VAR}$(( a + b ))$(( i++ ))(( i > 5 )) && echo big[[ -z "$VAR" ]][[ "$a" == "b" ]][[ "$a" =~ ^[0-9]+$ ]][ "$a" -gt 10 ]for i in {1..10}; do echo $i; donefor f in *.txt; do echo $f; donewhile read -r line; do echo $line; done < filewhile getopts ":a:b:" opt; do :; donecase "$x" in a) echo a;; b) echo b;; esacselect menu in opt1 opt2; do break; donecommand > file 2>&1cmd1 && cmd2cmd1 || cmd2cmd1 | cmd2tee -a log.txtset -eset -uset -o pipefailtrap cleanup EXITread -p "name: " nameprintf "%-10s %s\n" "$a" "$b"xargs -I{} cp {} dest/command -v <name>source ./env.sh参数展开与调试(REQ-02 补充) 12
${var:-default}${var:=default}${var:?message}${var#pattern}${var%pattern}${var/pattern/replace}${var^^}${#var}set -xbash -n script.shshopt -s nullglobgetopts "a:b" opt参数矩阵
| 参数 | 作用 | 示例 |
|---|---|---|
-x | 执行时打印每条命令,便于调试脚本 | bash -x script.sh |
-e | 命令失败时立即退出脚本 | set -e |
-u | 使用未定义变量时报错 | set -u |
-o pipefail | 管道任一环节失败即视为失败 | set -eo pipefail |
2> | 重定向标准错误 | cmd 2>/dev/null |
| | 管道,前一命令输出作为后一输入 | cat log | grep error | wc -l |
$() | 命令替换,捕获输出 | now=$(date +%F) |
&& / || | 前令成功/失败才执行后令 | make && make install |
-name / -type | find 按名/按类型查找 | find . -name "*.log" -mtime +7 |
-i | 忽略大小写(grep 等) | grep -ri error log/ |
易错点与避坑指南
现象脚本报 Permission denied 无法执行。
原因文件没有可执行位,或脚本首行 shebang 指向不存在的解释器。
处置chmod +x script.sh;确认首行 #!/usr/bin/env bash 且 bash 路径存在。
现象变量在子 shell/脚本中为空。
原因未用 export 导出,或作用域仅限当前 shell。
处置用 export VAR=val 让子进程可见;在脚本内统一用 local/全局变量声明。
现象for f in * 通配符没展开,被当成字面量。
原因目录为空时 nullglob 未开启,* 保持原样传给命令。
处置开启 shopt -s nullglob;或用 find ... -print0 | xargs -0 处理空目录情况。
现象重定向或管道把文件清空了。
原因命令如 cat file > file 在读取前先截断目标。
处置重定向到不同文件或临时文件再覆盖;小心 > 与 >> 的方向。
现象空格/特殊字符把文件名拆成多个参数。
原因未对变量加双引号,IFS 按空格/制表符切割。
处置始终用 "$var" 包裹变量;处理文件名用 while IFS= read -r line 与 find -print0。
现象rm 误删了不该删的文件。
原因通配符匹配过宽,或路径变量为空。
处置rm 前先 echo 看匹配结果;危险操作加 -i 确认;避免在变量为空时 rm -rf "$dir"/*。
排障路径
1调试脚本每一步
bash -x script.sh打印实际执行的命令与变量展开,定位逻辑错误。
2确认脚本语法无误
bash -n script.sh只做语法检查不执行,适合上线前校验。
3定位最近修改的大文件
find /var -type f -size +100M -mtime -1排查磁盘突增时快速定位可疑文件。
4统计日志中错误出现次数
grep -ci error /var/log/app.log快速评估错误规模,结合 tail 看最新样例。
命令示例
给变量设默认值
NAME=${NAME:-lzh}
echo "$NAME"${var:-default} 在变量未设或为空时取 default;改用 ${var-default} 只在完全未设时才取。
输出
lzh # NAME 未设时输出默认值;已设则输出原值
判断文件是否存在
if [[ -f /etc/nginx.conf ]]; then
echo exists
else
echo missing
fi用 [[ ]] 而非 [ ],支持 && 与 || 且不会错误分词;变量务必用双引号包裹,避免空值时语法报错。
输出
exists
获取脚本自身所在目录
DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
echo "$DIR"用 BASH_SOURCE[0] 而非 $0,这样即使脚本被 source 引入,拿到的也是其真实所在目录。
输出
/home/deploy/scripts
常见坑与注意事项
- 判断与算术一律优先用 [[ ]] 和 (( )),避免 [ ] 在空变量或带通配符的字符串下报语法错误。
- 双引号包变量是铁律:for i in $LIST、rm $f 这类写法不引号,遇空格或通配符会错拆词、误删文件。
- set -e 表示出错即停:脚本中某行失败会立即退出而非继续,重要脚本建议开启,防止失败后还在往下跑造成连锁问题。
- 函数内的变量默认是全局作用域,忘了写 local 会污染全局变量,同名变量极易踩到难以排查的坑。
- rm -rf 与 > 重定向都会真正删除或覆写文件,执行前先 echo 预览或做防护,避免误操作线上数据。
提示
- 变量赋值时等号两边不能有空格,否则会被解释为命令。
- 使用双引号包裹变量("$VAR")避免空格和特殊字符问题。
- [ ] 是 test 命令的语法糖,[[ ]] 是 Bash 扩展,支持更多功能如正则匹配。
常见问题
脚本开头常写的 set -euo pipefail 到底各自干什么?
set -e 遇错即退,但命令出现在 if/while/&&/|| 等条件位置或管道非末段时不会触发退出;-u 让引用未定义变量直接报错;-o pipefail 让管道的退出码取各段中最右的非零值,而不是只看末段。组合起来能尽早暴露错误,是健壮脚本的标配。
单引号和双引号包变量,为什么一个能展开一个不能?
双引号内 $变量、$(命令) 和反引号都会正常展开,单引号把内容当字面量完全不做处理,适合包路径、正则或确实无需展开的文本。含空格的路径务必用双引号包住变量,否则会被分词拆开。
$@ 和 $* 到底有什么区别?
不加引号时两者等价,都会把参数按空格分词;关键差别在加了引号之后:@ 形式把每个参数当作独立的一个词保留,* 形式把所有参数合并成一个字符串。遍历脚本参数时优先用加引号的 @ 形式。
想逐行读取一个文件去处理,怎么写才不含糊?
用 while IFS= read -r line; do ...; done < file,IFS= 防止裁掉行首尾空白,-r 防止把反斜杠当转义。别用 for line in $(cat file),那会按空白把内容拆成词而丢失每行的结构。
脚本里怎么判断上一条命令成功与否,又怎样主动让它失败?
$? 保存紧邻上一条命令的退出码,0 表示成功、非 0 表示失败,先把它存进变量再判断最稳妥。主动退出非 0 用 exit 1,返回 0 表示成功;配合 set -e,脚本遇到未捕获的失败会自动退出。
由 巧匠 维护
公开更新于 2026年9月10日,内容持续校对官方文档。