Как отследить выполнение команд в shell-скрипте с помощью трассировки оболочки
В этой статье из цикла отладки shell-скриптов мы объясним третий режим отладки shell-скриптов, то есть трассировку shell-скриптов, и рассмотрим несколько примеров, чтобы продемонстрировать, как он работает и как его можно использовать.
Предыдущая часть этой серии ясно проливает свет на два других режима отладки shell-скриптов: подробный режим и режим проверки синтаксиса, с простыми для понимания примерами того, как включить отладку shell-скриптов в этих режимах.
- Как включить режим отладки скриптов оболочки в Linux — часть 1
- Как выполнять проверку синтаксиса в режиме отладки в 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 частей.