You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在Bash中捕获命令的标准输出与错误输出,如何避免使用eval?

问题:规避eval实现命令stdout/stderr捕获的最优方案

关于eval的使用存在诸多警告,多数开发者认为应尽量规避该命令。但尝试多种方法后,发现不使用eval就会出现大量错误。需求是捕获命令的标准输出(stdout)与错误输出(stderr),当前实现的run函数如下:

run() {
...
    result=$(eval "$*" 2> "tee" -a "$_logfile" >&2)
...
}

另外,使用"$*"而非"$@"是为了避免shellcheck的SC2294警告(eval会抵消数组的优势),给tee加引号是为了避免SC2238警告(重定向到/从命令名而非文件)。测试的命令示例为:

run "yq --input-format xml --output-format props <\"$xmlfile\""

想知道是否有更优的实现方式?

更优实现方案

方案1:数组传递命令(推荐,无eval)

直接将命令作为数组参数传递给run函数,既保留参数边界,又彻底规避eval,同时解决shellcheck相关警告:

run() {
    local _logfile="your_log_path.log"
    # 捕获stdout到result,stderr同时写入日志和原stderr通道
    result="$("$@" 2> >(tee -a "$_logfile" >&2))"
}

调用时无需手动转义引号,写法更直观:

run yq --input-format xml --output-format props < "$xmlfile"

优势:

  • 完全消除eval带来的安全风险和解析歧义
  • $@会保留每个参数的原始边界,不会因空格、特殊字符导致参数拆分错误
  • 进程替换>(tee ...)实现stderr分流,逻辑清晰,不会触发SC2238警告

方案2:支持复杂shell语法的替代方案

如果需要处理包含重定向、管道等shell内置语法的复杂命令,可使用bash -c替代eval,安全性更高:

run() {
    local _logfile="your_log_path.log"
    # 用子shell执行命令字符串,保留shell语法支持
    result="$("$SHELL" -c "$1" 2> >(tee -a "$_logfile" >&2))"
}

调用时用单引号包裹命令字符串,避免变量提前展开:

run 'yq --input-format xml --output-format props < "$xmlfile"'

内容的提问来源于stack exchange,提问作者duise

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 23:40:25