I have a trap method which neither access global variables nor receive variables using $*
. It looks like this:
#!/usr/bin/env bash
set -euo pipefail
IFS=$'\n\t'
declare -a arr
finish_exit() {
echo "* = $*"
echo "arr = ${arr[*]}"
}
trap 'finish_exit "${arr[@]}"' EXIT
main() {
arr =("hello")
arr =("world")
}
main | tee -a /dev/null
The script prints ''.
If I remove the | tee -a ...
snippet, the script prints 'hello\nworld' twice as expected.
Now, how can I pipe the output to a logfile WITHOUT loosing all context?
One solution would be to route everything from the script call, like so:
./myscript.sh >> /dev/null
, but I think there should be a way to do this inside the script so I can log EVERY call, not just those run by cron.
Another solution I investigated was:
main() {
...
} >> /dev/null
But this will result in no output on the interactive shell.
Bonus karma for explanations why this subshell will "erase" global variables before the trap function is being called.
CodePudding user response:
will make trap method not see global variables
The subshell does "sees" global variables, it does not execute the trap.
why this subshell will "erase" global variables
From https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html :
Command substitution, commands grouped with parentheses, and asynchronous commands are invoked in a subshell environment that is a duplicate of the shell environment, except that traps caught by the shell are reset to the values that the shell inherited from its parent at invocation.
how can I pipe the output to a logfile WITHOUT loosing all context?
#!/bin/bash
exec 1> >(tee -a logfile)
trap 'echo world' EXIT
echo hello
or
{
trap 'echo world' EXIT
echo hello
} | tee -a logfile
And research: https://serverfault.com/questions/103501/how-can-i-fully-log-all-bash-scripts-actions and similar.
The following script:
#!/usr/bin/env bash
set -euo pipefail
{
set -euo pipefail
IFS=$'\n\t'
declare -a arr
finish_exit() {
echo "* = $*"
echo "arr = ${arr[*]}"
}
trap 'finish_exit "${arr[@]}"' EXIT
main() {
arr =("hello")
arr =("world")
}
main
} | tee -a /dev/null
outputs for me:
* = hello
world
arr = hello
world
I added that set -o pipefail
before the pipe, to preserve the exit status.