bash: escape de linhas individuais de '-x' ecoando

9

No bash, quando rodando com a opção -x , é possível dispensar comandos individuais do eco?

Estou tentando tornar a saída o mais organizada possível, por isso estou executando determinadas partes do meu script em um subshell com set +x . No entanto, a linha set +x em si ainda é ecoada e não adiciona informações valiosas à saída.

Lembro-me de volta aos antigos .bat dias, quando rodando com echo on , linhas individuais poderiam ser isentadas iniciando-as com @ . Existe algum equivalente em bash?

#!/bin/bash -x

function i_know_what_this_does() {
  (
    set +x
    echo do stuff
  )
}

echo the next-next line still echoes 'set +x', is that avoidable?
i_know_what_this_does
echo and we are back and echoing is back on

Ao executar o acima, a saída é:

+ echo the next-next line still echoes 'set +x,' is that 'avoidable?'
the next-next line still echoes set +x, is that avoidable?
+ i_know_what_this_does
+ set +x
do stuff
+ echo and we are back and echoing is back on
and we are back and echoing is back on
    
por clacke 02.01.2013 / 10:03

3 respostas

16

xtrace output vai para stderr, então você pode redirecionar stderr para /dev/null :

ikwtd() {
  echo do stuff
} 2> /dev/null

Se você ainda quiser ver os erros dos comandos executados dentro das funções, você pode fazer

ikwtd() (
  { set +x; } 2> /dev/null # silently disable xtrace
  echo do stuff
)

Observe o uso de (...) em vez de {...} para fornecer um escopo local para essa função por meio de um subshell. bash , já que a versão 4.4 agora suporta local - como no shell Almquist para tornar opções locais para a função (semelhante a set -o localoptions em zsh ), então você pode evitar a subshell fazendo:

ikwtd() {
  { local -; set +x; } 2> /dev/null # silently disable xtrace
  echo do stuff
}

Uma alternativa para bash 4.0 a 4.3 seria usar a variável $BASH_XTRACEFD e ter um descritor de arquivo dedicado aberto em /dev/null para isso:

exec 9> /dev/null
set -x
ikwtd() {
  { local BASH_XTRACEFD=9; } 2> /dev/null # silently disable xtrace
  echo do stuff
}

Como bash não tem a capacidade de marcar um fd com o sinalizador close-on-exec , isso tem o efeito colateral de vazar o fd para outros comandos.

Veja também este locvar.sh que contém algumas funções para implementar o escopo local para variáveis e funções em scripts POSIX e também fornece com trace_fn e untrace_fn funções para torná-las xtrace d ou não.

    
por 02.01.2013 / 10:53
2

A razão pela qual set +x é impresso é que set -x significa "imprimir o comando que você está prestes a executar, com expansões, antes de executá-lo . Portanto, o shell não sabe que você quero que ele não imprima coisas até depois de ter impresso a linha dizendo para não imprimir as coisas. Pelo que eu sei, não há como impedir que isso aconteça.

    
por 02.01.2013 / 10:16
0

Esta é a solução que você está procurando:

function xtrace() {
  # Print the line as if xtrace was turned on, using perl to filter out
  # the extra colon character and the following "set +x" line.
  (
    set -x
    # Colon is a no-op in bash, so nothing will execute.
    : "$@"
    set +x
  ) 2>&1 | perl -ne 's/^[+] :/+/ and print' 1>&2
  # Execute the original line unmolested
  "$@"
}

O comando original é executado no mesmo shell em uma transformação de identidade. Pouco antes de executar, você obtém um xtrace não recursivo dos argumentos. Isso permite xtrace os comandos que você gosta sem spam stederr com cópias duplicadas de cada comando "echo".

# Example
echo "About to do something complicated ..."
xtrace do_something_complicated
    
por 27.08.2015 / 21:23