The main problem you need to solve is how to get both the execution of time and the assignment of a variable in the same shell without a temporary file. Almost every Bash method provides the ability for a pipeline to output one thing to another or capture command output; it has one side working in a subshell.
Here is one way to do this without a temporary file, but I’ll warn you, it’s not very, it does not migrate to other shells, and this requires at least Bash 4:
coproc co { cat; }; times 1>&${co[1]}; eval "exec ${co[1]}>&-"; mapfile -tu ${co[0]} times_a
I will break this for you:
coproc co { cat; }
This creates a coprocess; a process that runs in the background, but you are given pipes to talk to standard input and standard output, which are FDs ${co[0]} (standard from cat ) and ${co[1]} (standard in cat ), The commands are executed in a subshell, so we cannot do any of our goals there (run times or read into a variable), but we can use cat to simply pass the input to the output and then use this channel to communicate with times and mapfile in the current shell.
times >&${co[1]};
Run times , redirecting your standard to the standard cat command code.
eval "exec ${co[1]}>&-"
Close the input end of the cat . If we do not, cat will continue to wait for input, leaving it open, and mapfile will continue to wait for it, as a result of which your shell will hang. exec , when no commands are passed, simply applies its redirects to the current shell; redirect to - closes FD. We need to use eval because Bash seems to have problems with exec ${co[1]}>&- , interpreting FD as a command instead of the redirect part; using eval allows you to replace this variable first and then execute.
mapfile -tu ${co[0]} times_a
Finally, we really read the data from the standard from the coprocess. We managed to run the times and mapfile in this shell and not use temporary files, although we used a temporary process as a pipeline between the two commands.
Note that this has a subtle race. If you execute these commands one by one, and not as one command, the latter is unsuccessful; because when you close the standard cat value, it terminates, causing the coprocess to exit, and the FDs must be closed. It seems that when running on just one line, the mapfile runs fast enough so that the coprocess is still open when it starts and, therefore, it can read from the channel; but I can get lucky. I did not understand a good way around this.
All said, it’s much easier to just write a temporary file. I would use mktemp to generate the file name, and if you're in a script, add a trap to make sure you clear your temporary file before exiting:
tempnam=$(mktemp) trap "rm '$tempnam'" EXIT times > ${tempnam} mapfile -t times_a < ${tempnam}