Quando você chega ao pescoço em jacarés, é fácil esquecer que o objetivo era drenar o pântano.
- provérbio popular
A pergunta é sobre echo, e, no entanto, a maioria das respostas até agora se concentrou em como ocultar um set +xcomando. Há uma solução muito mais simples e direta:
{ echo "Message"; } 2> /dev/null
(Reconheço que talvez eu não tivesse pensado nisso { …; } 2> /dev/null
se não tivesse visto nas respostas anteriores.)
Isso é um pouco complicado, mas, se você tiver um bloco de echocomandos consecutivos , não precisará fazer isso em cada um individualmente:
{
echo "The quick brown fox"
echo "jumps over the lazy dog."
} 2> /dev/null
Observe que você não precisa de ponto e vírgula quando possui novas linhas.
Você pode reduzir a carga de digitação usando a idéia do kenorb
de abrir /dev/nullpermanentemente em um descritor de arquivo não padrão (por exemplo, 3) e depois dizendo em 2>&3vez de 2> /dev/nullo tempo todo.
As quatro primeiras respostas no momento da redação deste documento exigem fazer algo especial (e, na maioria dos casos, complicado)
toda vez que você faz um echo. Se você realmente deseja que todos os echo comandos suprimam o rastreamento de execução (e por que não?), Você pode fazê-lo globalmente, sem alterar muito código. Primeiro, notei que os aliases não são rastreados:
$ myfunc()
> {
> date
> }
$ alias myalias="date"
$ set -x
$ date
+ date
Mon, Oct 31, 2016 0:00:00 AM # Happy Halloween!
$ myfunc
+ myfunc # Note that function call is traced.
+ date
Mon, Oct 31, 2016 0:00:01 AM
$ myalias
+ date # Note that it doesn’t say + myalias
Mon, Oct 31, 2016 0:00:02 AM
(Observe que os seguintes trechos de script funcionam se o shebang for #!/bin/sh, mesmo se /bin/shfor um link para o bash. Mas, se o shebang for #!/bin/bash, você precisará adicionar um shopt -s expand_aliasescomando para que os aliases funcionem em um script.)
Então, para o meu primeiro truque:
alias echo='{ set +x; } 2> /dev/null; builtin echo'
Agora, quando dizemos echo "Message", estamos chamando o alias, que não é rastreado. O alias desativa a opção de rastreamento, enquanto suprime a mensagem de rastreamento do setcomando (usando a técnica apresentada primeiro na resposta do usuário5071535 ) e, em seguida, executa o echocomando real . Isso nos permite obter um efeito semelhante ao da resposta do usuário5071535 sem precisar editar o código a cada echo comando. No entanto, isso deixa o modo de rastreamento desativado. Não podemos colocar um set -xno alias (ou pelo menos não facilmente) porque um alias permite apenas que uma string seja substituída por uma palavra; nenhuma parte da cadeia de alias pode ser injetada no comando
após os argumentos (por exemplo, "Message"). Então, por exemplo, se o script contiver
date
echo "The quick brown fox"
echo "jumps over the lazy dog."
date
a saída seria
+ date
Mon, Oct 31, 2016 0:00:03 AM
The quick brown fox
jumps over the lazy dog.
Mon, Oct 31, 2016 0:00:04 AM # Note that it doesn’t say + date
portanto, você ainda precisa ativar a opção de rastreamento novamente após exibir as mensagens - mas apenas uma vez após cada bloco de echocomandos consecutivos :
date
echo "The quick brown fox"
echo "jumps over the lazy dog."
set -x
date
Seria bom se pudéssemos fazer o set -xautomático depois de um echo- e podemos, com um pouco mais de truque. Mas antes de apresentar isso, considere isso. O OP está começando com scripts que usam um #!/bin/sh -exshebang. Implicitamente, o usuário pode remover o xdo shebang e ter um script que funcione normalmente, sem rastreamento de execução. Seria bom se pudéssemos desenvolver uma solução que retenha essa propriedade. As primeiras respostas aqui falham nessa propriedade porque ativam o rastreio após as echoinstruções após , incondicionalmente, sem considerar se ela já estava ativada.
Esta resposta conspicuamente falha em reconhecer esse problema, pois substitui echosaída com saída de rastreamento; portanto, todas as mensagens desaparecem se o rastreamento estiver desativado. Agora, apresentarei uma solução que ativa o rastreamento após uma echodeclaração condicionalmente - apenas se ela já estiver ativada. Fazer o downgrade para uma solução que ative o retorno incondicionalmente é trivial e é deixado como um exercício.
alias echo='{ save_flags="$-"; set +x;} 2> /dev/null; echo_and_restore'
echo_and_restore() {
builtin echo "$*"
case "$save_flags" in
(*x*) set -x
esac
}
$-é a lista de opções; uma concatenação das letras correspondentes a todas as opções definidas. Por exemplo, se as opções ee xestiverem definidas, $-haverá um amontoado de letras que inclui ee x. Meu novo alias (acima) salva o valor de $-antes de desativar o rastreio. Em seguida, com o rastreamento desativado, ele lança o controle sobre uma função shell. Essa função faz o real echo
e depois verifica se a xopção foi ativada quando o alias foi chamado. Se a opção estava ativada, a função a ativa novamente; se estiver desativado, a função o deixará desativado.
Você pode inserir as sete linhas acima (oito, se você incluir um shopt) no início do script e deixar o resto em paz.
Isso permitiria que você
- para usar qualquer uma das seguintes linhas shebang:
#! / bin / sh -ex
#! / bin / sh -e
#! / bin / sh –x
ou simplesmente#! / bin / sh
e deve funcionar como esperado.
- ter código como
comando
(shebang) 1 comando 2
comando 3
set -x
comando 4
comando 5
comando 6
set + x
comando 7
comando 8
comando 9
e
- Os comandos 4, 5 e 6 serão rastreados - a menos que um deles seja um
echo; nesse caso, ele será executado, mas não rastreado. (Mas, mesmo que o comando 5 seja um echo, o comando 6 ainda será rastreado.)
- Os comandos 7, 8 e 9 não serão rastreados. Mesmo se o comando 8 for um
echo, o comando 9 ainda não será rastreado.
- Os comandos 1, 2 e 3 serão rastreados (como 4, 5 e 6) ou não (como 7, 8 e 9), dependendo da inclusão do shebang
x.
PS Descobri que, no meu sistema, posso deixar de fora a builtinpalavra - chave na minha resposta do meio (aquela que é apenas um apelido echo). Isto não é surpreendente; o bash (1) diz que, durante a expansão do alias,…
... uma palavra idêntica a um alias sendo expandido não é expandida uma segunda vez. Isso significa que é possível usar um alias lspara ls -F, por exemplo, e o bash não tenta expandir recursivamente o texto de substituição.
Não é de surpreender que a última resposta (aquela com echo_and_restore) falhe se a builtinpalavra-chave for omitida 1 . Mas, estranhamente, funciona se eu excluir o builtine alternar a ordem:
echo_and_restore() {
echo "$*"
case "$save_flags" in
(*x*) set -x
esac
}
alias echo='{ save_flags="$-"; set +x;} 2> /dev/null; echo_and_restore'
__________
1 Parece dar origem a um comportamento indefinido. eu tenho visto
- um loop infinito (provavelmente por causa de recursão ilimitada),
- uma
/dev/null: Bad addressmensagem de erro e
- um core dump.
echo +x; echo "$*"; echo -xem um apelido, eu gostaria de vê-lo.