A armadilha é herdada por um subshell?

14

Eu tentei um script a seguir:

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

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

A saída para o script acima foi:

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

No entanto, eu esperava que a armadilha fosse chamada na saída foo1também, que é chamada em um subshell.

  • Isso é esperado?
  • É trapherdado por um subshell?
  • Se sim, em que caso é trapherdado por um subshell?
Bhagyesh Dudhediya
fonte

Respostas:

10

Os manipuladores de interceptação nunca são herdados por subshells. Isso é especificado pelo POSIX :

Quando um subshell é inserido, os traps que não estão sendo ignorados são definidos para as ações padrão.

Observe que os sinais ignorados ( trap '' SIGFOO) permanecem ignorados no subshell (e também nos programas externos lançados pelo shell).

Gilles 'SO- parar de ser mau'
fonte
3
No bash, você pode set -E, para que sub-conchas herdem armadilhas, mas é MUITO complicado acertar (pelo menos na minha experiência).
precisa saber é o seguinte
Não sei se isso funciona para todas as armadilhas. Eu sei que funciona para ERR
yosefrow
4

trapnão é propagado para subshells, mas algumas maneiras permitem que o subshell relate as armadilhas do shell pai e outras não. Fiz alguns testes em macos com bash.

Lançamento do GNU bash, versão 4.4.12 (1) (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, versão 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

É bom saber que trap_output="$(trap)"isso funcionará para capturar a saída de interceptação. Não consigo pensar em outra maneira de fazê-lo se isso não funcionasse além de fazer trap >trap_output_filea saída para um arquivo (o fifo não funcionará bash 3.2.57) e depois lê-lo novamente comtrap_output="$(<trap_output_file)"

O fifo não funciona bash 3.2.57porque trap &está vazio, bash 3.2.57mas não estábash 4.4.12

Lançamento do GNU bash, versão 4.4.12 (1) (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, versão 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
dosentmatter
fonte
2

trap as definições não são propagadas para subcascas.

Verifique por:

trap "echo bla" 1 2 3"

(trap)

esperto
fonte
2
Muitos shells tratam (trap)como um caso especial, para que o subshell possa relatar (mas não realmente usar) as armadilhas do shell pai. Portanto, esse teste nem sempre é confiável.
JigglyNaga
Ele funciona com a Shell Bourne e é derivados: ksh88, bosh(Schily Bourne Shell) e heirloom-sh. Você está correto: ksh93se comporta de maneira diferente.
schily
Ele não funciona no bash, usado pelo script em questão.
JigglyNaga
Bem, funciona no bash: bashnão produz nada se você ligar (trap).
schily 12/05