Поиск по сайту:

Как отследить выполнение команд в shell-скрипте с помощью трассировки оболочки


В этой статье из цикла отладки shell-скриптов мы объясним третий режим отладки shell-скриптов, то есть трассировку shell-скриптов, и рассмотрим несколько примеров, чтобы продемонстрировать, как он работает и как его можно использовать.

Предыдущая часть этой серии ясно проливает свет на два других режима отладки shell-скриптов: подробный режим и режим проверки синтаксиса, с простыми для понимания примерами того, как включить отладку shell-скриптов в этих режимах.

  1. Как включить режим отладки скриптов оболочки в Linux — часть 1
  2. Как выполнять проверку синтаксиса в режиме отладки в shell-скриптах – Часть 2

Трассировка оболочки просто означает трассировку выполнения команд в сценарии оболочки. Чтобы включить трассировку оболочки, используйте опцию отладки -x.

Это указывает оболочке отображать все команды и их аргументы в терминале по мере их выполнения.

Ниже мы будем использовать приведенный ниже скрипт sys_info.sh оболочки, который кратко выводит дату и время работы вашей системы, количество пользователей, вошедших в систему, и время работы системы. Тем не менее, он содержит синтаксические ошибки, которые нам нужно найти и исправить.

#!/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

Сохраните файл и сделайте скрипт исполняемым. Скрипт может быть запущен только пользователем root, поэтому используйте команду sudo для его запуска, как показано ниже:

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

Из приведенного выше вывода мы можем видеть, что команда сначала выполняется, прежде чем ее вывод подставляется в качестве значения переменной.

Например, дата была впервые выполнена, и ее вывод был заменен на значение переменной DATE.

Мы можем выполнить проверку синтаксиса, чтобы отобразить только синтаксические ошибки следующим образом:

$ sudo bash -n sys_info.sh 

Если мы критически посмотрим на сценарий оболочки, то поймем, что в операторе if отсутствует закрывающее слово fi. Поэтому давайте добавим его, и теперь новый скрипт должен выглядеть так, как показано ниже:

#!/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

Снова сохраните файл и вызовите его как root, а также проведите некоторую проверку синтаксиса:

$ sudo bash -n sys_info.sh

Результат нашей операции проверки синтаксиса выше по-прежнему показывает, что в нашем скрипте в строке 21 есть еще одна ошибка. Таким образом, нам еще предстоит внести некоторую коррекцию синтаксиса.

Если мы еще раз проанализируем скрипт, то увидим, что ошибка в строке 21 связана с отсутствием закрывающей двойной кавычки ( ") в последней команде echo внутри функции print_sys_info.

Мы добавим закрывающую двойную кавычку в команду echo и сохраним файл. Измененный скрипт приведен ниже:

#!/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

Теперь синтаксически проверьте скрипт еще раз.

$ sudo bash -n sys_info.sh

Приведенная выше команда не выдаст никакого вывода, потому что наш скрипт теперь синтаксически правильный. Мы также можем проследить выполнение скрипта во второй раз, и он должен работать хорошо:

$ sudo bash -x sys_info.sh

Теперь запустите скрипт.

$ sudo ./sys_info.sh

Важность трассировки выполнения скриптов оболочки

Трассировка сценариев оболочки помогает нам выявлять синтаксические ошибки и, что более важно, логические ошибки. Возьмем, к примеру, функцию check_root в сценарии оболочки sys_info.sh, которая предназначена для определения того, является ли пользователь привилегией root или нет, поскольку скрипт может выполняться только суперпользователем.

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

Магия здесь управляется выражением if [ "$UID" -ne "$ROOT_ID" ], как только мы не используем подходящий числовой оператор (-ne в данном случае, что означает не равно), мы получаем возможную логическую ошибку.

Предполагая, что мы использовали -eq ( означает равно), это позволило бы любому пользователю системы, а также пользователю root запустить скрипт, отсюда и логическая ошибка.

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

style="color: red;">Примечание: Как мы уже говорили ранее в начале этой серии, встроенная команда set shell может активировать отладку в определенном разделе сценария оболочки.

Поэтому строка ниже поможет нам найти эту логическую ошибку в функции, проследив ее выполнение:

Скрипт с логической ошибкой:

#!/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

Сохраните файл и вызовите скрипт, мы увидим, что обычный пользователь системы может запустить скрипт без sudo, как показано на выводе ниже. Это связано с тем, что значение USER_ID равно 100, что не равно корню ROOT_ID которое равно 0.

$ ./sys_info.sh

Ну вот и все, мы подошли к концу серии отладок сценариев оболочки, форму ответа ниже можно использовать для адресования любых вопросов или отзывов нам, касающихся этого руководства или всей серии из 3 частей.

Статьи по данной тематике: