Home > Software design >  piping main method to tee will make trap method not see global variables
piping main method to tee will make trap method not see global variables

Time:03-04

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.

  •  Tags:  
  • bash
  • Related