Pesquisa de site

Como rastrear a execução de comandos em Shell Script com Shell Tracing


Neste artigo da série de depuração de shell script, explicaremos o terceiro modo de depuração de shell script, que é o rastreamento de shell, e veremos alguns exemplos para demonstrar como ele funciona e como pode ser usado.

A parte anterior desta série esclarece claramente os outros dois modos de depuração de script de shell: modo detalhado e modo de verificação de sintaxe com exemplos fáceis de entender de como ativar o shell depuração de script nesses modos.

  1. Como ativar o modo de depuração de Shell Script no Linux – Parte 1
  2. Como executar o modo de depuração de verificação de sintaxe em scripts Shell – Parte 2

Rastreamento de shell significa simplesmente rastrear a execução dos comandos em um script de shell. Para ativar o rastreamento de shell, use a opção de depuração -x.

Isso direciona o shell para exibir todos os comandos e seus argumentos no terminal à medida que são executados.

Usaremos o script de shell sys_info.sh abaixo, que imprime brevemente a data e hora do sistema, o número de usuários logados e o tempo de atividade do sistema. No entanto, contém erros de sintaxe que precisamos encontrar e corrigir.

#!/bin/bash
#script to print brief system info

ROOT_ID="0"

DATE=`date`
NO_USERS=`who | wc -l`
UPTIME=`uptime`

check_root(){
    if [ "$UID" -ne "$ROOT_ID" ]; then
        echo "You are not allowed to execute this program!"
        exit 1;    
}

print_sys_info(){
    echo "System Time    : $DATE"
    echo "Number of users: $NO_USERS"
    echo "System Uptime  : $UPTIME
}

check_root
print_sys_info

exit 0

Salve o arquivo e torne o script executável. O script só pode ser executado pelo root, portanto, use o comando sudo para executá-lo conforme abaixo:

chmod +x sys_info.sh
sudo bash -x sys_info.sh

Pela saída acima, podemos observar que um comando é executado primeiro antes de sua saída ser substituída como o valor de uma variável.

Por exemplo, a data foi executada primeiro e sua saída foi substituída pelo valor da variável DATA.

Podemos realizar a verificação de sintaxe para exibir apenas os erros de sintaxe da seguinte forma:

sudo bash -n sys_info.sh 

Se olharmos criticamente para o shell script, perceberemos que a instrução if está faltando uma palavra fi de fechamento. Portanto, vamos adicioná-lo e o novo script deve ficar como abaixo:

#!/bin/bash
#script to print brief system info

ROOT_ID="0"

DATE=`date`
NO_USERS=`who | wc -l`
UPTIME=`uptime`

check_root(){
    if [ "$UID" -ne "$ROOT_ID" ]; then
        echo "You are not allowed to execute this program!"
        exit 1;
   fi    
}

print_sys_info(){
    echo "System Time    : $DATE"
    echo "Number of users: $NO_USERS"
    echo "System Uptime  : $UPTIME
}

check_root
print_sys_info

exit 0

Salve o arquivo novamente e invoque-o como root e faça algumas verificações de sintaxe:

sudo bash -n sys_info.sh

O resultado da nossa operação de verificação de sintaxe acima ainda mostra que há mais um bug em nosso script na linha 21. Portanto, ainda temos algumas correções de sintaxe a fazer.

Se examinarmos o script analiticamente mais uma vez, o erro na linha 21 é devido à falta de aspas duplas de fechamento ( ”) no último comando echo dentro do print_sys_info.

Adicionaremos as aspas duplas de fechamento no comando echo e salvaremos o arquivo. O script alterado está abaixo:

#!/bin/bash
#script to print brief system info

ROOT_ID="0"

DATE=`date`
NO_USERS=`who | wc -l`
UPTIME=`uptime`

check_root(){
    if [ "$UID" -ne "$ROOT_ID" ]; then
        echo "You are not allowed to execute this program!"
        exit 1;
    fi
}

print_sys_info(){
    echo "System Time    : $DATE"
    echo "Number of users: $NO_USERS"
    echo "System Uptime  : $UPTIME"
}

check_root
print_sys_info

exit 0

Agora verifique sintaticamente o script mais uma vez.

sudo bash -n sys_info.sh

O comando acima não produzirá nenhuma saída porque nosso script agora está sintaticamente correto. Também podemos rastrear a execução do script pela segunda vez e deve funcionar bem:

sudo bash -x sys_info.sh

Agora execute o script.

sudo ./sys_info.sh

Importância do rastreamento de execução do Shell Script

O rastreamento de script de shell nos ajuda a identificar erros de sintaxe e, mais importante, erros lógicos. Tomemos por exemplo a função check_root no shell script sys_info.sh, que tem como objetivo determinar se um usuário é root ou não, já que o script só pode ser executado pelo superusuário.

check_root(){
    if [ "$UID" -ne "$ROOT_ID" ]; then
        echo "You are not allowed to execute this program!"
        exit 1;
    fi
}

A mágica aqui é controlada pela expressão if statement [ "$UID" -ne "$ROOT_ID" ], uma vez que não utilizamos o operador numérico adequado ( -ne neste caso, o que significa diferente), acabamos com um possível erro lógico.

Supondo que usamos -eq (significa igual a), isso permitiria que qualquer usuário do sistema, bem como o usuário root, executasse o script, portanto, um erro lógico.

check_root(){
    if [ "$UID" -eq "$ROOT_ID" ]; then
        echo "You are not allowed to execute this program!"
        exit 1;
    fi
}

Nota: Como vimos antes no início desta série, o comando interno set shell pode ativar a depuração em uma seção específica de um script de shell.

Portanto, a linha abaixo nos ajudará a encontrar esse erro lógico na função rastreando sua execução:

O script com um erro lógico:

#!/bin/bash
#script to print brief system info

ROOT_ID="0"

DATE=`date`
NO_USERS=`who | wc -l`
UPTIME=`uptime`

check_root(){
    if [ "$UID" -eq "$ROOT_ID" ]; then
        echo "You are not allowed to execute this program!"
        exit 1;
    fi
}

print_sys_info(){
    echo "System Time    : $DATE"
    echo "Number of users: $NO_USERS"
    echo "System Uptime  : $UPTIME"
}

#turning on and off debugging of check_root function
set -x ; check_root;  set +x ;
print_sys_info

exit 0

Salve o arquivo e invoque o script, podemos ver que um usuário normal do sistema pode executar o script sem sudo como na saída abaixo. Isso ocorre porque o valor de USER_ID é 100, que não é igual ao ROOT_ID raiz, que é 0.

./sys_info.sh

Bem, por enquanto é isso, chegamos ao final da série de depuração de scripts de shell, o formulário de resposta abaixo pode ser usado para responder a qualquer dúvida ou feedback para nós, em relação a este guia ou a toda a série de 3 partes.