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?

Jack Nock
fonte

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
$
Tom
fonte
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
Radman
fonte
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
Soth
fonte
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
shuckc
fonte
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.

bhassel
fonte
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
$
nooj
fonte
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
Afriza N. Arief
fonte
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
Alan
fonte
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
RenRen
fonte
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
zzapper
fonte
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.

cnst
fonte
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

Karthik Arun
fonte
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
Paul Havens
fonte