Bash:将'times'内置的输出分配给变量

Ste*_*o M 7 bash

在一个bash脚本中我想将times内置的输出分配给一个数组变量,但我发现没有比这更好的方法了

tempnam=/tmp/aaa_$$_$RANDOM
times > ${tempnam}
mapfile -t times_a < ${tempnam}
Run Code Online (Sandbox Code Playgroud)

我将输出写入临时文件并在数组times_a中读回,因为管道或$(times)将在子shell中执行并返回错误的值.

没有临时文件的更好的解决方案?

Bri*_*ell 6

您需要解决的基本问题是如何time在同一个shell中执行和变量赋值,而不需要临时文件.几乎每个方法Bash都提供了一个东西到另一个东西的输出,或者捕获命令的输出,让一方在子shell中工作.

这是你可以在没有临时文件的情况下完成它的一种方法,但我会警告你,它不漂亮,它不能移植到其他shell,它至少需要Bash 4:

coproc co { cat; }; times 1>&${co[1]}; eval "exec ${co[1]}>&-"; mapfile -tu ${co[0]} times_a
Run Code Online (Sandbox Code Playgroud)

我会为你解决这个问题:

coproc co { cat; }
Run Code Online (Sandbox Code Playgroud)

这创造了一个协同过程; 在后台运行的进程,但是您可以使用管道与其标准输入和标准输出进行通信,这些是FD ${co[0]}(标准输出cat)和${co[1]}(标准输入cat).命令在子shell中执行,因此我们无法在那里执行任何一个目标(运行times或读取变量),但我们可以使用cat简单地将输入传递到输出,然后使用该管道进行通信以timesmapfile在当前shell.

times >&${co[1]};
Run Code Online (Sandbox Code Playgroud)

运行times,将其标准重定向到cat命令的标准.

eval "exec ${co[1]}>&-"
Run Code Online (Sandbox Code Playgroud)

关闭cat命令的输入端.如果我们不这样做,cat将继续等待输入,保持其输出打开,mapfile并将继续等待,导致您的shell挂起.exec,当没有传递命令时,只需将其重定向应用于当前shell; 重定向以-关闭FD.我们需要使用,eval因为Bash似乎遇到了麻烦exec ${co[1]}>&-,将FD解释为命令而不是重定向的一部分; using eval允许首先替换该变量,然后执行.

mapfile -tu ${co[0]} times_a
Run Code Online (Sandbox Code Playgroud)

最后,我们实际上从协同处理中读取了标准中的数据.我们设法在这个shell中运行timesmapfile命令,并且没有使用临时文件,尽管我们确实使用临时进程作为两个命令之间的管道.

请注意,这是一个微妙的比赛.如果逐个执行这些命令,而不是全部作为一个命令执行,则最后一个命令失败; 因为当你关闭cats标准时,它会退出,导致协同进程退出并关闭FD.看来,当在一行mapfile上执行时,执行速度足以使协同进程在运行时仍然打开,因此它可以从管道中读取; 但我可能会很幸运.我还没有找到一个很好的解决方法.

总而言之,写出临时文件要简单得多.我将用于mktemp生成文件名,如果您在脚本中,请添加陷阱以确保在退出之前清理临时文件:

tempnam=$(mktemp)
trap "rm '$tempnam'" EXIT
times > ${tempnam}
mapfile -t times_a < ${tempnam}
Run Code Online (Sandbox Code Playgroud)