HiveBrain v1.2.0
Get Started
← Back to all entries
patternbashMinor

An atexit for Bash

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
forbashatexit

Problem

I wrote the following atexit implementation for Bash

#! /bin/bash

set -e

ATEXIT=()

function atexit_handler
{
  local EXPR
  for EXPR in "${ATEXIT[@]}"; do
    echo "evaluating $EXPR"
    eval "$EXPR" || true
  done
}

trap atexit_handler EXIT

function atexit ()
{
  local EXPR
  for EXPR in "$@"; do
    ATEXIT+=("$EXPR")
  done
}

atexit true
atexit false
atexit "echo bye"

false


I am wondering, if this is possible without the use of eval.

Solution

I don't think it's possible without the eval. A close candidate might be:

atexit_handler() {
  local EXPR
  for EXPR in "${ATEXIT[@]}"; do
    echo "evaluating $EXPR"
    $EXPR || true
  done
}


But this won't work with non-trivial expressions like this:

atexit 'for i in "a b" c; do echo $i; done'


Using the function keyword in function declaration like this is an outdated practice:

function atexit_handler
{
  local EXPR
  for EXPR in "${ATEXIT[@]}"; do
    echo "evaluating $EXPR"
    eval "$EXPR" || true
  done
}


Use the more modern style I wrote in the previous example above.

Instead of this:

for EXPR in "$@"; do
    ATEXIT+=("$EXPR")
  done


A simpler way to iterate over $@:

for EXPR; do
    ATEXIT+=("$EXPR")
  done


But actually, as @etan-reisner pointed out in a comment, it's silly to loop here when you can add the entire arg list in one swift move:

ATEXIT+=("$@")

Code Snippets

atexit_handler() {
  local EXPR
  for EXPR in "${ATEXIT[@]}"; do
    echo "evaluating $EXPR"
    $EXPR || true
  done
}
atexit 'for i in "a b" c; do echo $i; done'
function atexit_handler
{
  local EXPR
  for EXPR in "${ATEXIT[@]}"; do
    echo "evaluating $EXPR"
    eval "$EXPR" || true
  done
}
for EXPR in "$@"; do
    ATEXIT+=("$EXPR")
  done
for EXPR; do
    ATEXIT+=("$EXPR")
  done

Context

StackExchange Code Review Q#67417, answer score: 7

Revisions (0)

No revisions yet.