编程 Bash 5.3 的命令替换 ${ command; }:省掉 fork,副作用留在当前 shell

2026-10-02 21:03:49

Bash 5.3 的命令替换 ${ command; }:省掉 fork,副作用留在当前 shell

Bash 5.3 于 2025 年夏发布,距 5.2 约三年。这一版的改动集中在脚本性能上。

参考:

命令替换的新形式

新增了一种在当前 shell 执行上下文中执行命令的命令替换,两种写法:

  • ${ command; } 捕获命令的标准输出,不 fork 子进程,也不经过管道。
  • ${| command; } 在当前 shell 中执行,命令完成后把结果放进 REPLY 变量。
# 旧写法:fork 子进程 + 管道
out=$(printf '%s' "$x")

# 5.3:在当前 shell 执行,stdout 直接捕获进 out
out=${ printf '%s' "$x"; }

# 5.3:在当前 shell 执行,结果放进 REPLY
${| printf '%s' "$x"; }
out=$REPLY

和 $(command) 相比,省掉的是 fork 和管道开销。在循环里大量做字符串处理时,这部分省下来是可观的。

取舍也来自同一处:命令在当前 shell 上下文里执行,副作用会留下。变量赋值、cd、函数定义、set 之类状态的改动,都会作用到当前 shell,而不是随子进程退出一起消失。所以这类替换适合用在无副作用的纯计算/字符串处理上;有状态改动的命令还是用 $(...) 更稳。

其他新特性

  • GLOBSORT:新变量,决定路径名补全/展开结果的排序方式。关键字有 name、size、blocks、mtime、atime、ctime、numeric、none,可升序或降序。

    GLOBSORT=size
    
  • compgen 新增 -V varname:把生成的补全写入指定变量,而不是打印到标准输出。

    compgen -V candidates -W "start stop restart"
    
  • read 新增 -E:使用 readline,并带上默认的 bash 补全(包括可编程补全)。也就是读输入时也能按 Tab 补全。

    read -E -p "file: " f
    
  • source 新增 -p PATH:用 PATH 参数替代 $PATH 来搜索文件。

    source -p /opt/app/lib utils.sh
    
  • BASH_MONOSECONDS:新的动态变量,若系统有单调时钟,返回其值。适合做不计入系统时间调整的耗时测量。

  • $TIMEFORMAT 允许最多 6 位精度(此前为 3 位)。

  • bash_source_fullpath shopt 选项:让 bash 把完整路径写入 BASH_SOURCE,并可在 configure 时设置默认值。

  • fltexpr:新的可加载内建,像 let 那样做浮点算术。

  • MULTIPLE_COPROCS 现在默认启用。

  • wait -n 现在也能返回已通知过用户的终止进程替换与作业。

  • 若 [[ 中使用的正则编译失败,会打印错误信息;检查 #! 脚本前两行再判断是否为二进制。

源码层面

Bash 5.3 的源码更新以符合 C23,这意味着 Bash 不再能用 K&R 风格的 C 编译器编译。

Readline

Readline 是 Bash 用于命令行编辑、历史与补全的库。这一版的新特性:

  • search-ignore-case 可绑变量:增量与非增量历史搜索忽略大小写。

    set search-ignore-case on
    
  • execute-named-command:从标准输入读取一个 readline 命令名并执行,emacs 模式默认绑到 M-x。

  • export-completions:把某个词的候选补全按既定格式写到标准输出,供其它进程消费。

构建

各发行版仓库会陆续收录 5.3;如果暂时找不到包,可以从源码构建。先装 build-essential,它依赖 libc6-dev、gcc、g++、make。

复制全文 生成海报 Bash Shell Linux 脚本 运维

推荐文章

程序员茄子在线接单