Como fazer eco dos comandos do shell à medida que são executados


912

Em um script de shell, como ecoar todos os comandos de shell chamados e expandir qualquer nome de variável?

Por exemplo, dada a seguinte linha:

ls $DIRNAME

Gostaria que o script execute o comando e exiba o seguinte

ls /full/path/to/some/dir

O objetivo é salvar um log de todos os comandos do shell chamados e seus argumentos. Existe talvez uma maneira melhor de gerar esse log?

Respostas:


1043

set -xou set -o xtraceexpande variáveis ​​e imprime um pequeno sinal de + antes da linha.

set -vou set -o verbosenão expande as variáveis ​​antes da impressão.

Use set +xe set +vpara desativar as configurações acima.

Na primeira linha do script, pode-se colocar #!/bin/sh -x(ou -v) para ter o mesmo efeito que set -x(ou -v) posteriormente no script.

O acima também funciona com /bin/sh.

Veja o wiki do bash-hackers em setatributos e depuração .

$ cat shl
#!/bin/bash                                                                     

DIR=/tmp/so
ls $DIR

$ bash -x shl 
+ DIR=/tmp/so
+ ls /tmp/so
$

7
Se você também quiser ver qual linha numerada está sendo executada, consulte stackoverflow.com/a/17805088/1729501
— user13107

3
e se eu quiser colorir o comando ao ecoar para diferenciar o comando e sua saída de resultados?
— Lewis Chan

11
E se eu quiser cantar cada comando através de um sintetizador de voz do tipo vocalóide ao ecoar, para que eu possa ouvir o que está fazendo à distância e também apreciar a música? Talvez com uma voz diferente para entradas e saídas.
— ADJenks

(O ABS tem uma longa história de não responder a pedidos de correção de exemplos de práticas inadequadas, a ponto de levar membros de longa data da comunidade a criar recursos concorrentes; moveu links para o wiki dos bash-hackers - o wiki do Wooledge ou o manual oficial do bash também seria um recurso melhor).
— Charles Duffy

317

set -x vai te dar o que você quer.

Aqui está um exemplo de script de shell para demonstrar:

#!/bin/bash
set -x #echo on

ls $PWD

Isso expande todas as variáveis ​​e imprime os comandos completos antes da saída do comando.

Resultado:

+ ls /home/user/
file1.txt file2.txt

21
Usar a palavra "detalhado" dessa maneira não realiza nada. Você pode fazer set -o verboseou set -v(apenas "detalhado") ou set -o xtraceou set -x(apenas "xtrace") ou set -xv(ambos) ou set -o xtrace -o verbose(ambos).
— Pausado até novo aviso.

isso funciona bem, mas lembre-se de que o "detalhado" substitui $ 1
— JasonS

90

Eu uso uma função para ecoar e executar o comando:

#!/bin/bash
# Function to display commands
exe() { echo "\$ $@" ; "$@" ; }

exe echo hello world

Quais saídas

$ echo hello world
hello world

Para comandos mais complicados, etc., você pode usar eval:

#!/bin/bash
# Function to display commands
exe() { echo "\$ ${@/eval/}" ; "$@" ; }

exe eval "echo 'Hello, World!' | cut -d ' ' -f1"

Quais saídas

$  echo 'Hello, World!' | cut -d ' ' -f1
Hello

Não há muitos votos para esta resposta. Existe uma razão para que seja uma má ideia? Trabalhou para mim, e parece ser exatamente o que estou procurando ...
— fru1tbat

1
Esta é a melhor resposta se você não quiser que todos os comandos sejam impressos. Evita a ++ set +xsaída quando desligado, além de parecer mais limpo. Porém, para apenas uma ou duas afirmações, a resposta de bhassel usando um subshell é a mais conveniente.
— Brent Faust

É isso que estou procurando! Não set +x, isso afeta todos os comandos, o que é demais!
— Hlung

11
Uma grande desvantagem disso é que a saída perde as informações de cotação. Você não pode diferenciar cp "foo bar" baze cp foo "bar baz", por exemplo. Portanto, é bom para exibir informações de progresso para um usuário; menos para depuração de saída ou gravação de comandos reproduzíveis. Casos de uso diferentes. Em zsh, você pode preservar a citação com o :qmodificador:exe() { echo '$' "${@:q}" ; "$@" ; }
— Andrew Janke

2
Eu não gosto desta resposta. Existem muitos casos em que o que você vê não é o que você obtém (especialmente com espaço em branco, aspas, caracteres escapados, substituições de variáveis ​​/ expressões etc.), portanto, não cole cegamente o comando echoed em um terminal e assuma que ele será executado o mesmo caminho. Além disso, a segunda técnica é apenas um hack e removerá outras instâncias da palavra evaldo seu comando. Portanto, não espere que funcione corretamente exe eval "echo 'eval world'"!
— mwfearnley

88

Você também pode alternar isso para linhas selecionadas em seu script, envolvendo-as set -xe set +x, por exemplo,

#!/bin/bash
...
if [[ ! -e $OUT_FILE ]];
then
   echo "grabbing $URL"
   set -x
   curl --fail --noproxy $SERV -s -S $URL -o $OUT_FILE
   set +x
fi

54

A resposta do shuckc para repetir as linhas de seleção tem algumas desvantagens: você também termina com o seguinte set +xcomando e perde a capacidade de testar o código de saída, uma $?vez que ele é sobrescrito pelo set +x.

Outra opção é executar o comando em um subshell:

echo "getting URL..."
( set -x ; curl -s --fail $URL -o $OUTFILE )

if [ $? -eq 0 ] ; then
    echo "curl failed"
    exit 1
fi

que lhe dará uma saída como:

getting URL...
+ curl -s --fail http://example.com/missing -o /tmp/example
curl failed

No entanto, isso implica a sobrecarga de criação de um novo subshell para o comando.


7
Ótima maneira de evitar a ++ set +xsaída.
— Brent Faust

3
Melhor ainda: substitua if [ $? -eq 0 ]por if (set -x; COMMAND).
— Amedee Van Gasse

35

Outra opção é colocar "-x" na parte superior do seu script, em vez de na linha de comando:

$ cat ./server
#!/bin/bash -x
ssh user@server

$ ./server
+ ssh user@server
user@server's password: ^C
$

Observe que isso não parece funcionar exatamente da mesma forma entre ./myScripte bash myScript. Ainda é bom ressaltar, obrigado.
— altendky

27

De acordo com o Guia Bash do TLDP para iniciantes: Capítulo 2. Escrevendo e depurando scripts :

2.3.1 Depurando em todo o script

$ bash -x script1.sh

...

Agora existe um depurador completo para o Bash, disponível no SourceForge . Esses recursos de depuração estão disponíveis nas versões mais modernas do Bash, a partir da 3.x.

2.3.2 Depurando parte (s) do script

set -x            # Activate debugging from here
w
set +x            # Stop debugging from here

...

Tabela 2-1. Visão geral das opções de depuração definidas

    Short  | Long notation | Result
    -------+---------------+--------------------------------------------------------------
    set -f | set -o noglob | Disable file name generation using metacharacters (globbing).
    set -v | set -o verbose| Prints shell input lines as they are read.
    set -x | set -o xtrace | Print command traces before executing command.

...

Como alternativa, esses modos podem ser especificados no próprio script, adicionando as opções desejadas à declaração do shell da primeira linha. As opções podem ser combinadas, como é geralmente o caso dos comandos UNIX:

#!/bin/bash -xv

18

Digite "bash -x" na linha de comando antes do nome do script Bash. Por exemplo, para executar foo.sh, digite:

bash -x foo.sh

11

Você pode executar um script Bash no modo de depuração com a -xopção .

Isso ecoará todos os comandos.

bash -x example_script.sh

# Console output
+ cd /home/user
+ mv text.txt mytext.txt

Você também pode salvar a opção -x no script . Basta especificar a -xopção no shebang.

######## example_script.sh ###################
#!/bin/bash -x

cd /home/user
mv text.txt mytext.txt

##############################################

./example_script.sh

# Console output
+ cd /home/user
+ mv text.txt mytext.txt

2
Também bash -vxfará o mesmo, mas sem interpolação de variável
— loa_in_

4

Para zsh, eco

 setopt VERBOSE

E para depuração,

 setopt XTRACE

2

Para cshe tcsh, você pode set verboseouset echo (ou pode até definir os dois, mas pode resultar em duplicação na maioria das vezes).

o verbose opção imprime praticamente a expressão exata do shell que você digita.

A echoopção é mais indicativa do que será executado através da desova.


http://www.tcsh.org/tcsh.html/Special_shell_variables.html#verbose

http://www.tcsh.org/tcsh.html/Special_shell_variables.html#echo


Special shell variables

verbose If set, causes the words of each command to be printed, after history substitution (if any). Set by the -v command line option.

echo If set, each command with its arguments is echoed just before it is executed. For non-builtin commands all expansions occur before echoing. Builtin commands are echoed before command and filename substitution, because these substitutions are then done selectively. Set by the -x command line option.


1
$ cat exampleScript.sh
#!/bin/bash
name="karthik";
echo $name;

bash -x exampleScript.sh

A saída é a seguinte:

insira a descrição da imagem aqui


Quais são as definições de cores para o seu terminal (RGB, numérico)?
— Peter Mortensen

1

Para permitir que comandos compostos sejam ecoados, eu uso evala exefunção plus Soth para fazer eco e executar o comando. Isso é útil para comandos canalizados que, de outra forma, mostrariam apenas nenhum ou apenas a parte inicial do comando canalizado.

Sem avaliação:

exe() { echo "\$ $@" ; "$@" ; }
exe ls -F | grep *.txt

Saídas:

$
file.txt

Com eval:

exe() { echo "\$ $@" ; "$@" ; }
exe eval 'ls -F | grep *.txt'

Quais saídas

$ exe eval 'ls -F | grep *.txt'
file.txt
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.