在一个bash
脚本中我想将times
内置的输出分配给一个数组变量,但我发现没有比这更好的方法了
tempnam=/tmp/aaa_$$_$RANDOM
times > ${tempnam}
mapfile -t times_a < ${tempnam}
Run Code Online (Sandbox Code Playgroud)
我将输出写入临时文件并在数组times_a中读回,因为管道或$(times)
将在子shell中执行并返回错误的值.
没有临时文件的更好的解决方案?
您需要解决的基本问题是如何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
简单地将输入传递到输出,然后使用该管道进行通信以times
和mapfile
在当前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中运行times
和mapfile
命令,并且没有使用临时文件,尽管我们确实使用临时进程作为两个命令之间的管道.
请注意,这是一个微妙的比赛.如果逐个执行这些命令,而不是全部作为一个命令执行,则最后一个命令失败; 因为当你关闭cat
s标准时,它会退出,导致协同进程退出并关闭FD.看来,当在一行mapfile
上执行时,执行速度足以使协同进程在运行时仍然打开,因此它可以从管道中读取; 但我可能会很幸运.我还没有找到一个很好的解决方法.
总而言之,写出临时文件要简单得多.我将用于mktemp
生成文件名,如果您在脚本中,请添加陷阱以确保在退出之前清理临时文件:
tempnam=$(mktemp)
trap "rm '$tempnam'" EXIT
times > ${tempnam}
mapfile -t times_a < ${tempnam}
Run Code Online (Sandbox Code Playgroud)