¿La trampa es heredada por una subshell?

14

Intenté un siguiente script:

#!/bin/bash
trap 'echo "touching a file" && touch $FILE' EXIT

foo1(){
        echo "foo1"
}
foo(){
        echo "foo"
        export FILE=${FILE:-/tmp/file1}
}
(foo1)
foo

El resultado para el script anterior fue:

[root@usr1 my_tests]# ./test.sh
foo1
foo
touching a file

Sin embargo, esperaba que también se llamara a trap en la salida foo1, que se llama en una subshell.

  • ¿Se espera esto?
  • ¿Es trapheredado por una subshell?
  • En caso afirmativo, ¿en qué caso lo traphereda una subshell?
Bhagyesh Dudhediya
fuente

Respuestas:

10

Los manipuladores de trampas nunca son heredados por subcapas. Esto lo especifica POSIX :

Cuando se ingresa un subshell, las trampas que no se ignoran se establecen en las acciones predeterminadas.

Tenga en cuenta que las señales ignoradas ( trap '' SIGFOO) permanecen ignoradas en el subshell (y también en los programas externos lanzados por el shell).

Gilles 'SO- deja de ser malvado'
fuente
3
En bash puedes set -Epara que las subcapas hereden las trampas, pero es REALMENTE difícil hacerlo bien (al menos en mi experiencia).
dragon788
No sé si esto funciona para todas las trampas. Sé que funciona para ERR
yosefrow
4

trapno se propaga a subcapas, pero algunas formas permiten que la subcadena informe las trampas de la capa principal y otras no. Hice algunas pruebas en macos con bash.

GNU bash, versión 4.4.12 (1) -release (x86_64-apple-darwin16.3.0):

trap 'echo hello' EXIT
trap # trap -- 'echo hello' EXIT
echo "$(trap)" # trap -- 'echo hello' EXIT
trap | cat # trap -- 'echo hello' EXIT
(trap) | cat # trap -- 'echo hello' EXIT
cat < <(trap) # empty
cat <<< "$(trap)" # empty
bash -c 'trap' # empty
trap & # trap -- 'echo hello' EXIT

GNU bash, versión 3.2.57 (1) -release (x86_64-apple-darwin16):

trap 'echo hello' EXIT
trap # trap -- 'echo hello' EXIT
echo "$(trap)" # trap -- 'echo hello' EXIT
trap > >(cat) # trap -- 'echo hello' EXIT
trap | cat # empty
(trap) | cat # empty
cat < <(trap) # empty
cat <<< "$(trap)" # empty
bash -c 'trap' # empty
trap & # empty

Es bueno saber que trap_output="$(trap)"funcionará para capturar la captura de salida. No puedo pensar en otra forma de hacerlo si eso no funcionó, además trap >trap_output_filede enviarlo a un archivo (no funcionará en Fifo bash 3.2.57) y luego volver a leerlo contrap_output="$(<trap_output_file)"

Fifo no funcionará bash 3.2.57porque trap &está vacío bash 3.2.57pero nobash 4.4.12

GNU bash, versión 4.4.12 (1) -release (x86_64-apple-darwin16.3.0):

mkfifo /tmp/fifo; trap >/tmp/fifo & trap_output=$(</tmp/fifo); rm -f /tmp/fifo; echo "$trap_output"
# trap -- 'echo hello' EXIT

mkfifo /tmp/fifo; trap_output=$(</tmp/fifo) & trap >/tmp/fifo; rm -f /tmp/fifo; echo "$trap_output"
# empty because trap_output=$(</tmp/fifo) sets the variable in a subshell

GNU bash, versión 3.2.57 (1) -release (x86_64-apple-darwin16):

mkfifo /tmp/fifo; trap >/tmp/fifo & trap_output=$(</tmp/fifo); rm -f /tmp/fifo; echo "$trap_output"
# empty because trap >/tmp/fifo & is empty since it uses trap &

mkfifo /tmp/fifo; trap_output=$(</tmp/fifo) & trap >/tmp/fifo; rm -f /tmp/fifo; echo "$trap_output"
# empty because trap_output=$(</tmp/fifo) sets the variable in a subshell
dosis
fuente
2

trap las definiciones no se propagan a subcapas.

Verificar por:

trap "echo bla" 1 2 3"

(trap)

astuto
fuente
2
Muchos shells se manejan (trap)como un caso especial, de modo que el subshell puede informar (pero no usar) las trampas del shell principal. Entonces esa prueba no siempre es confiable.
JigglyNaga
Funciona con la shell Bourne y su derivados: ksh88, bosh(schily Bourne Shell) y heirloom-sh. Tienes razón: se ksh93comporta de manera diferente.
schily
No funciona en bash, que utiliza el script en cuestión.
JigglyNaga
Bueno, funciona en bash: bashno genera nada si llamas (trap).
schily