Shell脚本优化核心是减少进程创建:提前计算date、用参数扩展替代cut、批量awk处理、[[ ]]替代[ ]、避免无谓管道和命令替换。

避免在循环中反复调用外部命令
频繁执行 date、grep、cut 等命令是 Shell 脚本变慢的最常见原因——每次调用都触发进程创建开销,尤其在千次以上循环里会指数级拖慢速度。
- 把
$(date +%s)提前算好,别写在for或while循环体里重复执行 - 用内置字符串操作替代
echo "$str" | cut -d',' -f2:改用${str#*,}和${str%,*} - 批量处理优先于逐行处理:用
awk一次性过滤+计算,而不是用while read line; do ...; done配合多个grep
用 [[ ]] 替代 [ ] 和 test
[ ] 是外部命令(通常是 /usr/bin/[),而 [[ ]] 是 Bash/Ksh/Zsh 的关键字,不产生子进程,支持正则匹配和更安全的变量展开。
-
[[ $path == /home/* ]] && echo "ok"安全且快;[ "$path" = "/home/*" ]不支持通配符,还可能因空格报错 -
[[ $val =~ ^[0-9]{3}$ ]]可直接正则校验;用expr或egrep就得多启一个进程 - 注意:
[[ ]]在 POSIX sh 中不可用,若需兼容 dash/sh,请坚持用[ ]并加引号保护变量
减少子 shell 创建,慎用管道和命令替换
每个 |、$(...)、`...` 都隐式启动子 shell,变量无法回传,还会带来 fork 开销。1000 次命令替换可能比单次 awk 多花 3 倍时间。
- 把
count=$(wc -l 改成read count _ (避免多一次进程) - 用
here-string替代管道输入:grep "foo" 比echo "$var" | grep "foo"少一个进程 - 大文本处理别拼接:
for f in *.log; do cat "$f"; done | gzip > all.gz→ 改用gzip *.log直接并行压缩
预编译正则与复用 awk 脚本逻辑
如果脚本中多次用到相同正则提取或字段计算,反复调用 sed/awk 是低效的。Bash 本身不缓存正则,但 awk 可以一次读完、多次处理。
awk '
BEGIN { pattern = "^([0-9]{4})-([0-9]{2})-([0-9]{2})" }
$0 ~ pattern {
year = substr($0, 1, 4)
month = substr($0, 6, 2)
if (month == "01") print "Jan", $0
}
' access.log- 避免写成:
grep -E '^\d{4}-\d{2}' file | while read l; do [[ $l =~ ^[0-9]{4} ]] && ...; done - 复杂字段拆分统一交给
awk -F'[[:space:]:]+' '{print $3,$7}',别用多个cut -d' '管道嵌套 -
awk脚本本身解析成本高,但执行期远快于等价的 Bash 字符串循环,尤其数据量超百行后优势明显
真实场景里,脚本是否“快”,往往取决于你有没有意识到:Bash 的每个空格、每对括号、每条竖线,都在悄悄 fork 进程。优化不是堆技巧,而是克制调用外部工具的冲动——能内置的用内置,能批量的别单干,能一次读完的别反复打开文件。










