log de script - log de comandos.

Atualizado em: 23/07/2006



Sobre este documento

Dicas e exemplos de log de scripts, salvar em arquivos resultados de comandos, direcionar toda a saída de um script para arquivo, mensagem de erro ou padrão ( stdout e stderr).

Depuração de script

Insira linhas para salvar o conteúdo de variáveis em arquivo, alguns exemplos.

echo " executou a linha tal " >> arquivo.log

echo "conteúdo da variável" >> arquivo.log

echo $VARIAVEL" >> arquivo.log

Verifique e salve o retorno de $?, faça testes com $?, use o if para conferir se executou o comando com sucesso e salve mensagen correspondete

echo $? >> arquivo.log

echo "comando executado com sucesso!" >> arquivo.log

Direcionar toda a saída de um script para arquivo, mensagem de erro ou padrão ( stdout e stderr).

Pode aplicar a um comando, linha de comando ou script, algumas formas de uso.

Redirecionar stdout e stderr para arquivo:

Redirecionar toda saida para um único arquivo

comando > arqsaida.log 2>&1

Redirecionar saida para arquivos distintos

comando 1> arqstdout.log 2> arqstderr.log

Descartar tudo, jogar no buraco negro /dev/null

comando > /dev/null 2>&1

script depurando script

script <arquivo_script> faz copia do conteúdo da tela em arquivo_script até que você digite o comando exit.

Útil para depuração.

Não confundir o nome do comando com arquivo de comandos que também recebe o nome de script, aqui o nome do comando é script mesmo.

Execute o script com a opção -xv para exibir as linhas de comando do seu script.

bash -xv seu-script

No CL10 ele vem no pacote util-linux, veja copia de parte do man no CL10

         script - gera um arquivo texto da sessão atual
  
  SINOPSE
         script [-a] [arquivo]
  
  DESCRIÇÃO
         script  gera  um  arquivo  texto de tudo que é impresso na tela. É útil
         para estudantes que precisam de uma cópia impressa de uma sessão inter-
         ativa, já que o script pode ser impresso mais tarde com lpr(1).
  
         Se  o  parâmetro arquivo é fornecido, script grava todos os diálogos em
         arquivo.  Se nenhum nome de arquivo é fornecido, o script é gravado  no
         arquivo typescript.
  
  OPÇÃO
         -a     Adiciona saída a arquivo ou typescript, mantendo o conteúdo ini-
                cial.
  
         O script termina quando se encerra o  shell  (control-D  para  sair  do
         Bourne SHell sh(1)), e exit, logout ou control-d (se ignoreeof não está
         definido) para C-shell, csh(1)).

exec - redirecionar para arquivo

Direcionar toda a saída de um script para arquivo, mensagem de erro ou padrão ( stdout e stderr).

Lembre que o redirecionador (.) cria arquivo novo, apaga os resultados já existentes nele, com (>>) dois sinal de maior acrescenta as mensagens no final do arquivo, mantendo os registros já existentes.

Faça testes com (exec), acrescente como no exemplo abaixo, na segunda linha do script ou a partir do ponto que deseja registrar.

Redireciona automaticamente todas as saídas do script para arquivo.log

Use seu editor para ver o que tem em arquivo.log

  #!/bin/bash
  exec 1>> arquivo.log 2>&1
  #seus comandos a partir daqui..

exec 2 - com resultado no console e arquivo.

  exec 2>> arquivo.log 2>&1

Outros exemplos....

  #!/bin/sh
  exec 2>> arqlog.txt
  #seus comandos a partir daqui..
  exit

variaveis em arquivo

Pode salvar conteúdo de variaveis em arquivo, isto não é recomendável porque o acesso em disco é mais lento. Como meio para depurar um script é muito útil, também para entender e expandir os comandos, vai dar mais mais trabalho mas facilita o entendimento e localização do problema.

Pode executar um script em um console e ficar monitorando com (tail -f arquivo) em outro console para ver as entradas e alterações no arquivo.

Serve como meio de passar dados para outro script, armazenar dados para comparação com variaveis do script, manter informação para uso futuro e outras apçicações.

Existem muitas maneiras, segue um exemplo para testar, copiar e colar as linhas abaixo, a primeira linha cria o arquivo, a segunda passa o conteúdo dele para variavel vartam e na terceira linha exibe o conteúdo da variável que é o mesmo do arquivo /tmp/vartemp1

echo "duas palavras" >> /tmp/vartemp1

vartam=$(cat /tmp/vartemp1)

echo $vartam

  zago@suse64:/tmp> echo "duas palavras" >> /tmp/vartemp1
  zago@suse64:/tmp> vartam=$(cat /tmp/vartemp1)
  zago@suse64:/tmp> echo $vartam
  duas palavras

Exemplo de um script que guarda o IP em arquivo para comparação futura com download via wget do IP atual

Este script fica em /etc/cron.hourly, portanto executado de hora em hora, envia e-mail somente quando altera o IP, observe que trabalha com dois arquivos; /tmp/iparquivo e /tmp/ipatual.txt

cat /etc/cron.hourly/ipteste.sh

  #!/bin/bash
  cd /tmp
  ARQUIVOIP=`cat /tmp/iparquivo`
  # ultimo ip enviado
  # estação com IP 192.168.1.3, precisa buscar o IP na net
  wget http://whatismyip.com/ -q -O ipatual
  cat ipatual | grep "<TITLE" | awk {'print $3'} > /tmp/ipatual.txt
  IPATUAL=`cat /tmp/ipatual.txt`
  # comparar IP atual com iparquivo
  echo $IPATUAL
  echo $ARQUIVOIP
  if [ $IPATUAL != $ARQUIVOIP ]
    then
    echo $IPATUAL
    # enviar e-mail
    DESTINATARIO="zagolinux@gmail.com"
    ASSUNTO="Novo IP de .."
    MENSAGEM="Novo IP $IPATUAL"
    echo "$MENSAGEM" | mail -s "$ASSUNTO" "$DESTINATARIO"
    echo $IPATUAL > /tmp/iparquivo
  fi

Manipulando arquivos

Sempre faça backup antes de qualquer alteração direta no arquivo, a principio os resultados são exibidos na saida padrão (console), como exemplo o resultado do comando cat aplicado em arquivo, seja para viusualizar, numerar linhas ou remover linhas em branco, isto não modifica o arquivo, caso queira aplicar as modificações no aruivo, precisa reidirecionar a saida para outro arquivo e depois renomear o de origem para depois renomear o modificado para o nome de origem.

sed permite alterar diretamente no arquivo com a opção (-i) altera o proprio arquivo, mais um bom motivo para fazer copia antes de qualquer ação.

time - contar tempo de execução

O utilitário 'time' é usado como uma espécie de cronômetro para medir o tempo de execução de um comando especificado. Ele pode ajudar na otimização de programas para velocidade máxima, assim como vários outros usos.

Instale o pacote time, consulte também a página do manual (man time)

Medir o tempo para executar uma tarefa, considere que temos mais de uma opção para executar a mesma tarefa, como exemplo, fazer uma troca ou pesquisa em um arquivo, pode se usar awk, sed, cat+grep e muitos outros. Dependendo da lógica pode dar voltas. Com certeza existe uma forma mais lenta e outra mais rápida para fazer o mesmo trabalho. O time entra como ferramenta de contagem do tempo de cada script ou comando, deve ser usado como ferramenta de depuração para obter melhor desempenho.

Procure usar time com diferentes ferramentas para manipular o mesmo arquivo, use procedimento diferente para fazer a mesma alteração e compare os resultados.

Em script procure indicar o caminho do executável e salvar o resultado em arquivo para posterior consulta, formato de comando para uso em script, nos exemplos abaixo salva o resultado em /tmp/timelog.

/usr/bin/time -o /tmp/timelog comando mais as diretivas quando houver.

  /usr/bin/time -o /tmp/timelog tar -zcvf guiaz-`date +%d%m%y`.tar.gz  /home/zago/guiaz

Exemplo para medir o tempo que md5sum demora para conferir uma imagem ISO do CL10

md5sum -c cl10_cd1.iso.md5

Agora o mesmo comando com time para contar o tempo decorrido, coloque o comando entre "picas" veja o exemplo do comando e o resultado:

  [root@faqcl10 cl10_cd1]# time sh -c 'md5sum -c cl10_cd1.iso.md5'
  cl10_cd1.iso: A soma coincide
  
  real    0m16.495s
  user    0m3.097s
  sys     0m1.914s

Quando quiser descartar o resultado do comando e pegar somente o tempo decorrido, acrescente > /dev/null para descartar as mensagens do comando que está entre "picas", veja que no resultado abaixo não exibe:

cl10_cd1.iso: A soma coincide

  [root@faqcl10 cl10_cd1]# time sh -c 'md5sum -c cl10_cd1.iso.md5' > /dev/null
  
  real    0m17.000s
  user    0m3.049s
  sys     0m1.930s

Outros exemplos em linha de comando:

Descompactar em outro diretório, o modo verbose do tar "v" exibe os resultados e no final o tempo decorrido.

time tar -zxvf homezago-221104.tar.gz -C /tmp

Retornar somente o tempo gasto para executar uma tarefa:

time sh -c 'tar -zxvf homezago-221104.tar.gz | grep comandos.txt' > /dev/null

Tempo decorrido na pesquisa com grep

time grep "comandos.txt" -r /home/zago/guiaz/

Conta somente o tempo

time sh -c 'grep "comandos.txt" -r /home/zago/guiaz/' > /dev/null

Salvar data e hora em que o comando foi executado.

Entre as linhas de comando do script pode inserir linhas para salvar comentarios, dada e hora e outras informações, para salvar uma linha com data e hora pode usar algo neste formato.

echo "`date +%d/%m/%y" "%H:%M` data atual" >> arquivo.log

Normalmente interessa somente a hora e minuto, a linha de comando fica assim.

echo "`date +%H:%M` data atual" >> arquivo.log

Outra opção, passar o resultado para xargs e incluir hora e minutos em cada mensagem (resultado do script).

Neste caso não precisa acrescentar as linhas no script, passe o resultado do script para xargs, use o echo mais date para incluir hora e minutos na mensagem, ou outros detalhes que desejar, execute seu script neste formato.

./seuscript.sh | xargs echo $(date +%H:%M) >> arquivo.log

mensagens de comandos sem mensagens

Verbose de comandos

Muitos comandos não exibe mensagem alguma na forma default, como exemplo o comando mkdir para criar um diretório.

mkdir /tmp/teste

A linha de comando acima não retorna mensagem no console, quando redirecionar a saida também não salva mensagem alguma.

Quase todos os comandos possuem a opção (-v) ou outro parametro que emite as mensagens de sucesso ou erro dos comandos, são informações úteis para debug, compare o resultado do exemplo acima com este

  mkdir -v /tmp/teste
  mkdir: created directory `/tmp/teste'
  
  mkdir -v /tmp/teste
  mkdir: não é possível criar o diretório `/tmp/teste': Arquivo existe

Usando redirecionador para arquivo, estas mensagens serão gravadas nele.

Pode acrescentar um (echo mensagem) antes da linha de comando, algo como.

  echo "criar o diretório de testes " > /tmp/arqlog.txt
  mkdir -v /tmp/teste
  echo $? >> /tmp/arqlog.txt

Pode usar um if para testar se o diretório foi criado ou não, veja opções para trabalhar com o resultado de ($?)

Personalize as mensagens enviadas pelo echo, alguns exemplos.

  Inserir duas linhas em branco, dois tab, a mensagem e mais duas linhas em branco.
  echo -e "\n\n\t\tTarefa exclusiva de root\n\n"
  
  Esta mensagem "Tarefa exclusiva de root" aparece em destaque no console ou arquivo quando redirecionada 
  
  echo -e "\n\n\t\tTarefa exclusiva de root\n\n" >> /tmp/arqlog.txt
  
  Ou enter e espaços depois de abrir aspas também insere linhas em branco, bash não interpreta os enter e espaços entre aspas duplas, veja o resultado, cole no console este exemplo.

echo "

Tarefa exclusiva de root

"

  
  Salvar em arquivo, mensagem mais o retorno de status ($?) do ultimo comando executado.
  echo "comando tal retornou estatus $? >> /tmp/arqlog.txt

Gravando data e hora da execução.

Pode usar time para contar o tempo decorrido, ou simplesmente acrescentar uma linha para salvar data e hora no arquivo de log, algo como neste exemplo.

echo "[$(date +%d/%m/%Y-%H:%M:%S)] " >> /tmp/arqlog.txt

echo "comando tal executado em [$(date +%d/%m/%Y-%H:%M:%S)] " >> /tmp/arqlog.txt

set -x exibindo a linha de comando

set -x em script é muito interessante, exibe a linha de comando antes de sua execução. Em script com redirecionamento para arquivo, salva também a linha de comando.

cat testset.sh

#!/bin/bash set -x mkdir -v /tmp/teste chown zago /tmp/teste ls -la /tmp/teste

Resultado; mostra a linha de comando com sinal (+) ./testset.sh

  + mkdir -v /tmp/teste
  mkdir: não é possível criar o diretório `/tmp/teste': Arquivo existe
  + chown zago /tmp/teste
  + ls -la /tmp/teste
  total 2
  drwxr-xr-x   2 zago users   48 2006-06-20 22:45 .
  drwxrwxrwt  36 root root  2080 2006-06-20 23:30 ..

Outra opção, chame o script neste formato de comando.

bash -x ./seusript.sh

Tem o mesmo resultado que usar (set -x) dentro do script, exibe as linhas de comando no console.

veja também o resultado com -v e xv

sh -v seuscript.sh

bash -xv seuscript.sh

$? tratamento de erro - restultado do comando

Cada comando executado em shell ou script tem um codigo de retorno, útil em script para conferir se falhou ou foi executado com sucesso, este resultado fica armazenado na variavel $?, ele muda a cada comando, tanto faz se foi na linha de comando ou dentro do script, em cada comando esta variavel é atualizada, "echo $?" sempre exibirá o resultado do ultimo comando.

  Retornando:
   0 (zero) significa que o comando anterior foi executado com sucesso.
   1 (um) e qualquer valor diferente de zero ( != 0) indica que ocorreu algum
      erro.
   2  erro nos comandos do script, geralmete erro de sintaxe, digitação,
   127 = command not found, pra quando digita comando não existente.

Exemplos:

  [zago@faqcl10 tmp]$ touch meuteste
  [zago@faqcl10 tmp]$ echo $?
  0
  [zago@faqcl10 tmp]$ ls meusdoc
  ls: meusdoc: Arquivo ou diretório não encontrado
  [zago@faqcl10 tmp]$ echo $?
  1
  [zago@faqcl10 tmp]$ ls
  meuteste
  [zago@faqcl10 tmp]$ echo $?
  0

Explicando:

retornou 1 (um) quando falhou o comando "ls meusdoc" e retornou zero para os demais comandos que foram executados sem problemas.

Cuidado pra não repetir "echo $?" porque ele também é um comando e altera o retorno, portanto vale somente o primeiro "echo $?" depois do comando.

Script para testar esta condição:

cat /tmp/testar

  #!/bin/bash
  mkdir /tmp/teste
  if [ $? -eq 0 ];then
    echo $?
    echo "comando executado com sucesso!"
  else
    echo $?
    echo "falha na execução do comando."
    exit
  fi

Neste exemplo a linha "if [ $? -eq 0 ]" verifica o retorno do comando "mkdir /tmp/teste" para saber se o seu mkdir foi bem sucedido ou não. Na primeira vez que executar retorna zero, depois passa a retornar 1 porque o diretório já existe e falha na criação do diretório, portanto indicando este erro "1" em $?.

.bash_history - ultimos comandos executados

Histórico dos comandos são registrados no arquivo .bash_history dentro do home do usuário, conforme a configuração mantém os últimos 1.000 comandos.

Pode ser uma grande fonte de informação para descobrir o que o usuário executou via linha de comando, também nos casos se invasão, quando o invasor esquece de apagar, pode pegar os comandos que ele executou como root.

Tenha muito cuidado com este arquivo, pode revelar senhas, nos casos de copia da linha de comando para criar usuário e definir senha, isto fica registrado e outra pessoa pode ler este arquivo, neste caso pegar as senhas.

Como exemplo, esta rotina para criar usuários e senha no SUSE 10, para facilitar, basta copiar e colar no console estas linhas.

  usuario=zago
  senha=minhasenha
  useradd -m $usuario
  echo $senha | passwd --stdin $usuario
  ( echo $senha ; echo $senha ) | smbpasswd -s -a $usuario

Todas estas linhas vão automaticamente para o histórico do root em /root/.bash_history, quem tiver acesso ao histórico vai descobrir estas senhas.

Portando já sabe o que fazer, não use este meio de criar usuário, se usar este recurso deve apagar o histórico ou editar para remover as linhas indesejadas.

Sobre o .bash_history - Dicas e FAQ com mensagens da Linux-br
http://www.zago.eti.br/bash.txt

passo a passo

Tente resolver por parte, resolva um problema por vez, tente dividir script longo em pequenos scripts ou montar outro script para executar e testar a parte com dificuldade, isto facilita o entendimento e solução de problemas.

Provocar parada entre as linhas, ou após linha especifica do script, ajuda em scripts longos, utilize sleep, read, wait ou outra condição de parada, exemplo com sleep provocando uma parada de 3 segundos:

sleep 3

Acrescente esta linha depois da linha que deseja provocar a parada.

read Provoca uma parada até pressionar uma tecla.

Aprovei para exibir conteúdo de variável ou retorno de erro, coloque estas linhas antes da linha do sleep

Salve os resultados e conteudo das variaveis em arquivo texto, insira algumas linhas no script pra salvar os resultados parciais ou variaveis, use dois sinal de maior >>, por exemplo:

echo $variavel >> /tmp/meuteste.txt

Pode usar quantas linhas quiser e depois pesquisar no arquivo texto onde salvou.

LANG Idioma do sistema

A configuração de idioma interfere em muitos resultados, conforme a configuração da variável LANG o resultado pode totalmente diferente do esperado, falhar nos testes comparativos com expressões fixas em scripts, como exemplo os nomes do dia ou mes. Isto ocorre em muitas situações, portanto fique atendo nas comparações envolvendo parte fixa em scrip com dados coletados no sistema.

Scripts comparando dia da semana podem falhar coforme o teste e idioma.

Compare estes resultados:

  MDIA=$(LANG=pt_BR date '+%A')
  echo $MDIA
  quinta
  
  MDIA=$(LANG=en_US date '+%A')
  echo $MDIA
  Thursday

A parte decimal de valores deve usar , (virgula) com LANG pt_BR e . (ponto) com LANG en_US, exemplo sleep ,5 em ambiente cofigurado com pt_BR e sleep .5 com LANG en_US.

Script com erros em calculos, fique atento ao detalhe do idioma que pode mudar o resultado pela troca de virgula com ponto e vice-versa.

Veja qual o idioma em uso, digite no terminal:

echo $LANG

DEBUG em scripts

Debug é um recurso muito utilizado em programas.

Acho que DEBUG em scripts é um exagero, mas é um recurso interessante.

Pode ativar modo debug para localizar falhas em programas.

Debug no bash, inicie por este endereço.
http://bashdb.sourceforge.net/

Proucure no Google por algo como: debug script ~linux

Indicações

Dicas sobre log em geral.
http://www.zago.eti.br/log.html

Página principal sobre script em geral (FAQ)
http://www.zago.eti.br/script/A-menu-scripts.html

Página principal deste site (FAQ)
http://www.zago.eti.br/menu.html