Trap todos os comandos na função

0

Estou trabalhando com um conjunto de scripts com funções tratadas como somente leitura. As funções são mais do que apenas uma lista de comandos, por exemplo, pode haver loops e diretórios de mudança e até mesmo chamadas para outras funções:

func() {
    cd folder/
    run command1
    mkdir folder2/ ; cd folder2/
    run command2
}

Por um momento, fingindo que eu poderia mudar os scripts, para mostrar a você o que eu quero, um pode ser assim:

func() {
    cd folder/
    string[0]="command1" ; run command1 |& tee out0.log ; result[0]="$?" ; finished_command_number 0
    mkdir folder2/ ; cd folder2/
    string[1]="command2" ; run command2 |& tee out1.log ; result[1]="$?" ; finished_command_number 1
}

Portanto, para comandos que podem ser canalizados, mas não para cd ou loops, quero armazenar uma cadeia, armazenar a stdout (stderr), armazenar o código de saída e executar outro comando posteriormente. No entanto, eu não posso adicionar isso, deve ser feito no meu script que está invocando aquele com func ().

Para obter apenas a funcionalidade de chamada do comando post, tentei copiar a função e executá-la do meu script com um trap foo debug , mas isso não parece se propagar em funções. Eu não acho que copiar literalmente linha por linha funcionará porque os cd e loops não podem ser isolados, já que são instruções de controle em vez de comandos subshell.

Se as strings podem ser apenas uma função dos próprios comandos, ainda é útil.

    
por Timothy Swan 21.04.2018 / 00:31

2 respostas

1
#!/bin/bash
# test.sh
post() {
        echo "post [$BASH_COMMAND] [$?]"
        echo "== $RANDOM =="
}
set -o functrace
trap post debug
func() {
        . check.sh
        tryme |& tee out.txt
}
func

A saída pode ser filtrada pelas linhas marcadas com aleatório. Eu deveria testar isso ainda mais para ver o quão bem ele funciona com vários processos, mas parece funcionar bem com comandos de curta duração. Observe que o código de saída é atrasado por um comando, já que a depuração é aparentemente chamada primeiro.

#!/bin/bash
# check.sh
tryme() {
        echo "one"
        echo "two"
        mkdir -p hello
        cd hello/
        echo "three"
        false
        echo "four"
}

===

$ bash test.sh 
post [func] [0]
== 22542 ==
post [func] [0]
== 10758 ==
post [. check.sh] [0]
== 9115 ==
post [tryme 2>&1] [0]
== 11979 ==
post [tee out.txt] [0]
== 17814 ==
post [tryme 2>&1] [0]
== 22838 ==
post [echo "one"] [0]
== 5251 ==
one
post [echo "two"] [0]
== 18036 ==
two
post [mkdir -p hello] [0]
== 4247 ==
post [cd hello/] [0]
== 21611 ==
post [echo "three"] [0]
== 24685 ==
three
post [false] [0]
== 8557 ==
post [echo "four"] [1]
== 7565 ==
four
    
por 02.05.2018 / 00:15
1

Se eu estou lendo sua pergunta corretamente, você está procurando uma maneira de:

  • Capture stdout e stderr independentemente das saídas de uma chamada de função
  • Preservar o diretório de trabalho atual em relação a quaisquer alterações no decorrer da execução de uma função

Isso pode ser feito de maneira simples:

#!/bin/bash
stdout=/path/to/output.std
stderr=/path/to/output.err

somefunc() {
    : Do things
}

( somefunc arg1 arg2 ) >> $stdout 2>> $stderr

A execução da função em um subshell permitirá que ele faça o que for necessário com relação à alteração do diretório de trabalho e a saída para o stdout e o stderr normalmente. Quando o subshell é encerrado, o diretório de trabalho do script não é alterado e todas as saídas stdout e stderr são capturadas e redirecionadas para seus arquivos de log.

Adicionar uma matriz (global ou de outra forma) na qual capturar códigos de saída de comandos é trivial:

declare -a exitcodes
( exit 0 )
exitcodes+=( $? )
( exit 2 )
exitcodes+=( $? )
( exit 0 )
exitcodes+=( $? )

echo ${exitcodes[@]}
    
por 21.04.2018 / 00:50