在不使用子shell的情况下从bash函数捕获输出

在不使用子shell的情况下从bash函数捕获输出

我有一个 bash 脚本,在管道上监听命令。当它看到命令时就会运行它。但是,我希望它支持可以稍后调用的 bash 函数的“侧面加载”。

以下是一些输入/输出示例,可让您了解脚本应该执行的操作:

# left of the arrow is input, right of arrow is output
"echo 'test'" -> "test"
"_a() { echo 'test' }" -> ""
"_a" -> "test"

我让它对于普通命令运行良好,但是在尝试加载函数时遇到了问题。我怀疑这是因为我正在子 shell 中执行用户输入,因此父级将无法使用任何定义的函数来执行将来的命令。我曾尝试使用文件描述符将数据存储在(stdoutstderr)中eval,但永远无法使其工作。我目前有这样的事情:

exec 3>&1
eval 'echo "Hello World"' >&3
read -u 3 var
exec 3>&- 
echo "$var"

这可能吗?

答案1

这可能对你有用:

$ cat runcmd
#!/usr/bin/env bash

tmpout=$(mktemp) || exit
tmperr=$(mktemp) || exit
trap 'rm -f -- "$tmpout" "$tmperr"; exit' EXIT

while IFS= read -r -a cmd; do
    printf '==========\n'
    declare -p cmd

    eval "${cmd[@]}" > "$tmpout" 2>"$tmperr"

    readarray -t out < "$tmpout"
    readarray -t err < "$tmperr"

    declare -p out
    declare -p err
done

$ cat <<'EOF' | ./runcmd
echo 'test of echo with globbing * and variables $RANDOM and    spaces'
_a() { echo 'test of a()'; }
_a
awk 'BEGIN{print "multi line\noutput string"; print "and multi\nline error\nmessage" | "cat>&2"}'
EOF
==========
declare -a cmd=([0]="echo 'test of echo with globbing * and variables \$RANDOM and    spaces'")
declare -a out=([0]="test of echo with globbing * and variables \$RANDOM and    spaces")
declare -a err=()
==========
declare -a cmd=([0]="_a() { echo 'test of a()'; }")
declare -a out=()
declare -a err=()
==========
declare -a cmd=([0]="_a")
declare -a out=([0]="test of a()")
declare -a err=()
==========
declare -a cmd=([0]="awk 'BEGIN{print \"multi line\\noutput string\"; print \"and multi\\nline error\\nmessage\" | \"cat>&2\"}'")
declare -a out=([0]="multi line" [1]="output string")
declare -a err=([0]="and multi" [1]="line error" [2]="message")

但显然编写程序来执行作为输入提供的代码是危险的,所以请阅读Bash 常见问题解答:我试图将命令放入变量中,但复杂的情况总是失败!为什么应该在 bash 中避免评估以及我应该使用什么在实施任何这样做之前。

相关内容