| name | modern-bash |
| description | Modern Bash scripting with a functional programming mindset. Bash is essentially "string Lisp" - a language where everything is string manipulation, commands are functions, and pipelines are composition. Use when writing, refactoring, or analyzing Bash scripts with emphasis on static/dynamic semantics, functional patterns, and modern best practices. |
Modern Bash - The String Lisp
Core Philosophy: Bash = String Lisp
Bash的本质是字符串Lisp:
- 一切都是字符串 - 变量、输出、参数都是字符串
- 命令即函数 - 每个命令都是纯函数 (stdin → stdout)
- 管道即组合 -
| 是函数组合操作符
- 命令替换即求值 -
$(...) 是表达式求值
- 重定向即副作用 - 显式管理副作用
seq 1 100 | xargs -n1 | while read n; do echo $((n * 2)); done
result=$(echo "$input" | grep pattern | wc -l)
Agent Workflow
- 静态语义检查 - 分析语法结构、作用域、变量绑定
- 动态语义分析 - 理解执行流程、状态转换、副作用
- 函数式重构 - 减少副作用,增加可组合性
- 严格求值验证 - 确认参数展开、命令替换顺序
- 边界处理 - 空值、空格、特殊字符的防御性处理
Essential Patterns
1. 纯函数式命令 (Pure Functions)
add() {
echo $(( $1 + $2 ))
}
result=$(add 3 5)
global_var=0
impure_add() {
global_var=$(( global_var + $1 ))
}
2. 字符串作为数据结构
files="file1.txt file2.txt file3.txt"
for f in $files; do
echo "Processing: $f"
done
declare -A config=(
[host]="localhost"
[port]="8080"
)
echo "${config[host]}:${config[port]}"
3. 管道组合 (Function Composition)
cat data.txt \
| grep "ERROR" \
| cut -d' ' -f3 \
| sort \
| uniq -c \
| sort -rn
4. 命令替换作为表达式求值
for i in $(seq 1 3); do
echo $i
done
while read line; do
echo "Processing: $line"
done < <(generate_infinite_stream)
5. 词法作用域模拟
process_file() {
local filepath="$1"
local filename=$(basename "$filepath")
local temp_dir=$(mktemp -d)
local content
content=$(cat "$filepath")
trap "rm -rf '$temp_dir'" EXIT
}
Static Semantics (静态语义)
词法分析
KEYWORD: function, if, for, while, do, done, then, fi
IDENTIFIER: [a-zA-Z_][a-zA-Z0-9_]*
VARIABLE: $[0-9], $*, $@, $#, $?, $$, $!, $_, ${name}
SYMBOL: |, &, ;, (, ), {, }, <, >
作用域分析
for i in $(seq 1 10); do
:
done
local_scope_demo() {
local i
local count="${1:-10}"
for i in $(seq 1 "$count"); do
echo $i
done
}
类型系统 (弱类型检查)
assert_number() {
[[ "$1" =~ ^[0-9]+$ ]] || {
echo "Error: expected number, got '$1'" >&2
return 1
}
}
add_safe() {
assert_number "$1" && assert_number "$2" || return 1
echo $(( $1 + $2 ))
}
Dynamic Semantics (动态语义)
执行模型
for i in $(seq 1 $n); do
echo $i
done
副作用管理
cd_up() {
local n="${1:-1}"
local i
for i in $(seq 1 "$n"); do
cd .. || return $?
done
}
parent_dir() {
local n="${1:-1}"
local path="$PWD"
local i
for i in $(seq 1 "$n"); do
path=$(dirname "$path")
done
echo "$path"
}
求值策略
foo $(expensive_op) $(another_op)
[[ -f "$file" ]] && process "$file"
cmd="echo hello"
eval "$cmd"
Common Pitfalls
1. 未引用的变量展开
file_list=$(ls)
for f in $file_list; do echo "$f"; done
file_list=(*)
for f in "${file_list[@]}"; do echo "$f"; done
2. 作用域泄漏
for i in a b c; do :; done
echo "$i"
safe_loop() {
local i
for i in a b c; do :; done
}
3. 整数溢出/类型问题
echo $(( 2**63 ))
result=$(echo "2^100" | bc)
4. 命令替换的尾部换行
content=$(cat file.txt)
content=$(cat file.txt; echo x)
content=${content%x}
Functional Utilities
Map
map() {
local func="$1"
local item
while IFS= read -r item; do
"$func" "$item"
done
}
double() { echo $(( $1 * 2 )); }
seq 1 10 | map double
Filter
filter() {
local predicate="$1"
local item
while IFS= read -r item; do
"$predicate" "$item" && echo "$item"
done
}
is_even() { (( $1 % 2 == 0 )); }
seq 1 10 | filter is_even
Reduce / Fold
reduce() {
local func="$1"
local acc="$2"
local item
while IFS= read -r item; do
acc=$("$func" "$acc" "$item")
done
echo "$acc"
}
sum() { echo $(( $1 + $2 )); }
seq 1 10 | reduce sum 0
References