保留副作用并在单独的变量中捕获bash函数的标准输出和标准错误?



假设bash函数dump修改了一个变量,并将不同的内容打印给stdoutstderr:

function dump() {
var1=1
echo OUT
echo ERR 1>&2
}

变量var1可以在其调用者的上下文中定义,也可以最初由函数本身定义。如果在调用方中定义了var1,那么在函数dump中对var1的修改应该传播给调用方。如果var1最初是在dump内部定义的,则不需要是否将var1传播给调用者。

考虑到这个bash脚本可能运行在一个所有挂载的文件系统都是只读的并且没有挂载tmpfs的系统上,这个问题的解决方法不应该使用任何重定向到文件操作。该脚本可以在没有root权限或任何功能的情况下运行。像unshare这样的命令可能无法工作,因为不允许使用用户名称空间。您也可以假设bash内置的网络文件/dev/tcp/dev/udp已经打了补丁。

是否有办法在不同的变量中捕获dumpstdoutstderr,同时暴露变量修改(副作用)?

是否有办法在暴露变量修改(副作用)的同时捕获dump在不同变量中的标准输出和标准错误?

确定。只使用临时文件。例如:

stdoutf=$(mktemp)
stderrf=$(mktemp)
dump >"$stdoutf" 2>"$stderrf"
stderr=$(<"$stderrf")
sdtout=$(<"$stdoutf")
rm "$stderrf" "$stdoutf"

文件系统是只读的,没有挂载tmpfs

许多shell命令将停止工作。shell主要处理文件,没有文件shell很困难。不过,我猜/dev/shm必须挂载,您可以将其用作临时位置。

不使用任何重定向到文件的操作

啊,自找麻烦…无论如何,您可以在子进程内存中缓冲数据,并使用临时fifo或仅使用共享内存传输数据。您可以编写一个bash内置程序来调用mmap(),并在进程之间共享fd,并在那里存储数据并从父进程读取(我记得在GitHub上看到过这样一个程序的源代码,但我现在找不到它)。无论如何,这里有一个使用方便的coproc的示例:

#!/bin/bash
dump() {
var1=1
echo OUT
echo ERR 1>&2
}
bufferer() {
stdout=""
stderr=""
while IFS= read -r line; do
case "$line" in
stderr*) stderr+=${line#stderr}$'n'; ;;
stdout*) stdout+=${line#stdout}$'n'; ;;
esac
done
cat <<<"$stdout"
echo MARK
cat <<<"$stderr"
}
coproc { bufferer; }
exec 9>&"${COPROC[1]}"
dump > >(xxd -p | sed 's/^/stdout/' >&9) 2> >(xxd -p | sed 's/^/stderr/' >&9)
eval "exec ${COPROC[1]}<&-"
exec 9>&-
out=$(cat <&"${COPROC[0]}")
eval "exec ${COPROC[0]}<&-"
stdout=$(printf "%s" "${out%MARK*}" | xxd -p -r)
stderr=$(printf "%s" "${out#*MARK}" | xxd -p -r)
declare -p var1 stdout stderr

脚本输出:

declare -- var1="1"
declare -- stdout="OUT"
declare -- stderr="ERR"