«Работать добросовестно — значит: работать, повышая свою квалификацию, проявляя инициативу в совершенствовании продукции, технологий, организации работ, оказывая не предусмотренную должностными инструкциями помощь другим сотрудникам (включая и руководителей) в общей им всем работе.

Спец курс (Автоматизация процесса проектирования)/Лекция 2 (BASH)

Материал из Wiki
< Спец курс (Автоматизация процесса проектирования)
Версия от 01:42, 13 февраля 2018; Vidokq (обсуждение | вклад)

Это снимок страницы. Он включает старые, но не удалённые версии шаблонов и изображений.
Перейти к: навигация, поиск
Лекции SCRIPT

Лекции

Практические задания
Тесты

Табель успеваемости

Экзамен

Доп. материалы

Содержание

Объявление переменных: declare и typeset

  • Инструкции declare и typeset являются встроенными инструкциями (они абсолютно идентичны друг другу и являются синонимами) и предназначена для наложения ограничений на переменные. Это очень слабая попытка контроля над типами, которая имеется во многих языках программирования. Инструкция declare появилась в Bash, начиная с версии 2. Кроме того, инструкция typeset может использоваться и в ksh-сценариях.

Ключи инструкций declare/typeset

  • -r readonly (только для чтения)

declare -r var1 (declare -r var1 аналогично объявлению readonly var1)

  1. Это грубый эквивалент констант (const) в языке C. Попытка изменения таких переменных завершается сообщением об ошибке.
  • -i integer
#!/bin/bash
declare -i number
# Сценарий интерпретирует переменную "number" как целое число.
number=3
echo "number = $number"     # number = 3
number=three
echo "number = $number"     # number = 0
# Строка "three" интерпретируется как целое число.
  • Примечательно, что допускается выполнение некоторых арифметических операций над переменными, объявленными как integer, не прибегая к инструкциям expr или let.
  • -a array
#!/bin/bash
declare -a indices
#Переменная indices объявляется массивом.
  • -f functions
#!/bin/bash
#declare -f
#Инструкция declare -f, без аргументов, приводит к выводу списка ранее объявленных функций в сценарии.
#declare -f function_name
  • Инструкция declare -f function_name выводит имя функции function_name, если она была объявлена ранее.
-x export
declare -x var3
# Эта инструкция объявляет переменную, как доступную для экспорта.
 
var=$value
declare -x var3=373
  • Инструкция declare допускает совмещение объявления и присваивания значения переменной одновременно.
#!/bin/bash
 
func1 ()
{
echo Это функция.
}
 
declare -f        # Список функций, объявленных выше.
 
echo
 
declare -i var1   # var1 -- целочисленная переменная.
var1=2367
echo "переменная var1 объявлена как $var1"
var1=var1+1       # Допустимая арифметическая операция над целочисленными переменными.
echo "переменная var1 увеличена на 1 = $var1."
# Допустимая операция для целочисленных переменных
echo "Возможно ли записать дробное число 2367.1 в var1?"
var1=2367.1       # Сообщение об ошибке, переменная не изменяется.
echo "значение переменной var1 осталось прежним = $var1"
 
echo
 
declare -r var2=13.36         # инструкция 'declare' допускает установку свойств переменной
                              #+ и одновременно присваивать значение.
echo "var2 declared as $var2" # Допускается ли изменять значение readonly переменных?
var2=13.37                    # Сообщение об ошибке и завершение работы сценария.
 
echo "значение переменной var2 осталось прежним $var2" # Эта строка никогда не будет выполнена.
 
exit 0                        # Сценарий завершит работу выше.

Создание массивов

  • Массив - это переменная, в которой хранится несколько значений.
  • Любая переменная может использоваться как массив.
  • На максимальный размер массива ограничений нет и нет никаких других требований к элементам массива, за исключением лишь того, что элементы массива имеют индексы и значения индексов идут подряд.
  • Массивы начинаются с нулевого элемента: индекс первого элемента равен 0.
Косвенное объявление, задающее переменную типа массив, выполняется следующим образом:
ARRAY[INDEXNR]=value 
#INDEXNR рассматривается как арифметическое выражение, результат вычисления которого должен быть положительным числом.
  • Явное объявление массива выполняется с помощью встроенной команды declare:
declare -a ARRAYNAME
  • Также допускается объявление с указанием индекса, но индекс будет игнорироваться.
  • С помощью встроенных команд declare и readonly для массива можно определять атрибуты.
  • Атрибуты действуют для всех переменных в массиве, у вас не может быть смешанных массивов.
# Массив переменных можно также объявить с помощью инструкции присваивания следующего формата:
ARRAY=(value1 value2 ... valueN)
  • Каждое значение value в этом формате имеет вид [номериндекса =]строка.
  • Индекс не является обязательным.
  • Если он указан, то он используется в инструкции присваивания;
  • В противном случае в качестве индекса используется значение индекса, которое уже было назначено, плюс один.
  • Этот формат можно также использовать в команде declare.
  • Если индексы не указываются, индексация начинается с нуля.
  • Добавление отсутствующих или дополнительных элементов массива осуществляется следующим образом:
ARRAYNAME[indexnumber]=value
  • Помните, что во встроенной команде read есть параметр -a, который позволяет читать и назначать значения элементам массива.

Получение доступа к содержимому массива

  • Чтобы получить доступ к содержимому элемента в массиве, используйте фигурные скобки.

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

  • Если в качестве номера индекса указывается "@" или "*", то выдаются все элементы массива.
#!/bin/bash
ARRAY=(one two three)
echo ${ARRAY[*]}
# one two three
 
echo $ARRAY[*]
one[*]
 
echo ${ARRAY[2]}
#three
 
ARRAY[3]=four
 
echo ${ARRAY[*]}
#one two three four
  • Если переменная массива указывается без указания номера индекса, то в результате будет получено содержимое первого элемента массива, т. е. элемента с нулевым индексом.
  • Bash позволяет оперировать переменными, как массивами, даже если они не были явно объявлены таковыми.
string=abcABC123ABCabc
echo ${string[@]}               # abcABC123ABCabc
echo ${string[*]}               # abcABC123ABCabc
echo ${string[0]}               # abcABC123ABCabc
echo ${string[1]}               # Ничего не выводится!
                                # Почему?
echo ${#string[@]}              # 1
                                # Количество элементов в массиве.

Удаление переменных массивов

  • Для уничтожения массивов или элементов массива используется встроенная команда unset:
#!/bin/bash
unset ARRAY[1]
echo ${ARRAY[*]}
#one three four
 
unset ARRAY
 
echo ${ARRAY[*]}
#<--no output-->

Примеры массивов

Практические примеры использования массивов найти трудно. Вы легко найдете множество скриптов, которые в вашей системе, в действительности, ничего не делают, но в них используются массивы для вычисления математических рядов. И это будут одни из наиболее интересных примеров ... В большинстве скриптов всего лишь в упрощенном виде показывается, что вы, теоретически, можете делать с массивами. Причина этого состоит в том, что массивы являются сравнительно сложными структурами. Вы обнаружите, что большинство практических примеров, в которых используются массивы, уже реализованы в вашей системе, но на более низком уровне — на языке программирования C, на котором написаны большинство команд UNIX.
#!/bin/bash
# сможет ли пользователь, имеющий надлежащие права доступа, запускать скрипт с правильными аргументами.
if [ $(whoami) != 'root' ]; then
        echo "Must be root to run $0"
        exit 1;
fi
if [ -z $1 ]; then
        echo "Usage: $0 <path/to/httpd.conf>"
        exit 1
fi
 
httpd_conf_new=$1
httpd_conf_path="/usr/local/apache/conf"
login=htuser
 
#Имена хостов, которые необходимо сконфигурировать, перечислены в массиве farm_hosts
farm_hosts=(web03 web04 web05 web06 web07)
 
for i in ${farm_hosts[@]}; do
        su $login -c "scp $httpd_conf_new ${i}:${httpd_conf_path}"
        su $login -c "ssh $i sudo /usr/local/apache/bin/apachectl graceful"
 
done
exit 0
  • Следующий пример представил Дэн Рихтер (Dan Richter). Он столкнулся со следующей проблемой:
"... На сайте моей компании есть демонстрационные примеры, и каждую неделю кто-нибудь должен все их проверять. Поэтому у меня есть задание cron, которое 
заполняет массив возможными кандидатами; в задании cron для определения недели в году используется команда date +%W и для того, чтобы получить правильный 
индекс, выполняется операция по модулю. Счастливчик получает уведомление по электронной почте".
И ниже приводится способ ее решения:
#!/bin/bash
# This is get-tester-address.sh 
#
# First, we test whether bash supports arrays.
# (Support for arrays was only added recently.)
#
whotest[0]='test' || (echo 'Failure: arrays not supported in this version of
bash.' && exit 2)
 
#
# Our list of candidates. (Feel free to add or
# remove candidates.)
#
wholist=(
     'Bob Smith <bob@example.com>'
     'Jane L. Williams <jane@example.com>'
     'Eric S. Raymond <esr@example.com>'
     'Larry Wall <wall@example.com>'
     'Linus Torvalds <linus@example.com>'
   )
#
# Count the number of possible testers.
# (Loop until we find an empty string.)
#
count=0
while [ "x${wholist[count]}" != "x" ]
do
   count=$(( $count + 1 ))
done
 
#
# Now we calculate whose turn it is.
#
week=`date '+%W'`       # The week of the year (0..53).
week=${week#0}          # Remove possible leading zero.
 
let "index = $week % $count"   # week modulo count = the lucky person
 
email=${wholist[index]}     # Get the lucky person's e-mail address.
 
echo $email             # Output the person's e-mail address.
Затем этот скрипт будет использован в других скриптах, таких как следующий, в котором используется встраиваемый документ (here document):
 
email=`get-tester-address.sh`   # Find who to e-mail.
hostname=`hostname`             # This machine's name.
 
#
# Send e-mail to the right person.
#
mail $email -s '[Demo Testing]' <EOF
The lucky tester this week is: $email
 
Reminder: the list of demos is here:
    http://web.example.com:8080/DemoSites
 
(This e-mail was generated by $0 on ${hostname}.)
EOF

Подмножества и части строк

  • Подмножества и части строк
  • Обычно расширение имеет такую форму: ${PARAMETER:OFFSET:LENGTH}, где аргумент LENGTH необязателен. Итак, если вы хотите выбрать только определенное подмножество аргументов скрипта, вы можете использовать полную версию, чтобы показать, сколько аргументов следует выбрать. Например, ${@:4:3} обращается к трем аргументам, начиная с аргумента 4, а именно, к аргументам 4, 5 и 6. Вы можете использовать это расширение для выбора конкретных параметров помимо тех, которые доступны сразу, используя от $1 до $9 включительно. ${@:15:1} — способ вызова сразу 15 параметра.
  • Вы можете использовать расширение с конкретными параметрами, а также весь набор параметров, представленный при помощи $* или $@. В этом случае параметр обрабатывается как строка и число, представляющее собой сдвиг или длину. Например, если переменная x имеет значение «some value», то
${x:3:5}

будет иметь значение «e val».

Подстроки значений параметров в shell

#!/bin/bash
x=»some value»
echo «${x:3:5}»
e val

Размеры переменных

  • Вы уже видели, что $# указывает число параметров и что расширение ${PARAMETER:OFFSET:LENGTH} применяется и к конкретным параметрам, и к $* и $@, поэтому вас не должно удивить, что аналогичная конструкция, ${#PARAMETER}, может использоваться для определения размера конкретного параметра. Простая функция testlength, показанная в Листинге 10, иллюстрирует это. Попробуйте сделать это сами.

#!/bin/bash
testlength () { for p in «$@»; do echo ${#p};done }
testlength 1 abc «def ghi»
#1
#3
#7

Работа с шаблонами

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

Расширение шаблонов в shell Расширение Назначение

  • ${ПАРАМЕТР#СЛОВО} Shell расширяет СЛОВО как расширение имени файла и удаляет самое короткое соответствие шаблону, если оно имеется, с начала расширенного значения ПАРАМЕТРА. Использование ‘@’ или ‘$’ приводит к удалению по образцу для каждого параметра в списке.
  • ${ПАРАМЕТР##СЛОВО} Приводит к удалению самого длинного соответствия шаблону с начала вместо самого короткого.
  • ${ПАРАМЕТР%СЛОВО} Shell расширяет СЛОВО как расширение имени файла и удаляет самое короткое соответствие шаблону, если оно имеется, с конца расширенного значения ПАРАМЕТРА. Использование ‘@’ или ‘$’ приводит к удалению по образцу для каждого параметра в списке.
  • ${ПАРАМЕТР%%СЛОВО} Приводит к удалению самого длинного соответствия шаблону с конца вместо самого короткого.
  • ${ПАРАМЕТР/ОБРАЗЕЦ/ПОСЛЕДОВАТЕЛЬНОСТЬ} Shell расширяет ОБРАЗЕЦ как расширение имени файла и заменяет самое длинное соответствие шаблону, если оно имеется, расширенным значением ПАРАМЕТРА. Для соответствия образцам в начале расширенного значения ПАРАМЕТРА поставьте в начале ОБРАЗЦА # или %, если соответствие должно проверяться до конца. Если ПОСЛЕДОВАТЕЛЬНОСТЬ пуста, перемещение / может быть опущено и соответствия удаляются. Использование ‘@’ или ‘$’ приводит к замене образца для каждого параметра в списке.
  • ${ПАРАМЕТР//ОБРАЗЕЦ/ПОСЛЕДОВАТЕЛЬНОСТЬ} Выполняет замену для всех подходящих, а не только для первого.
#!/bin/bash
x=»a1 b1 c2 d2″
echo ${x#*1}
#b1 c2 d2
echo ${x##*1}
#c2 d2
echo ${x%1*}
#a1 b
echo ${x%%1*}
#a
echo ${x/1/3}
#a3 b1 c2 d2
echo ${x//1/3}
#a3 b3 c2 d2
echo ${x//?1/z3}
#z3 z3 c2 d2

Перенаправление потока вывода в файл

Bombilla amarilla - yellow Edison lamp.pngДескриптор файла -- это просто число, по которому система идентифицирует открытые файлы. Рассматривайте его как упрощенную версию указателя на файл.

  • COMMAND_OUTPUT > # Перенаправление stdout (вывода) в файл. Если файл отсутствовал, то он создается, иначе -- перезаписывается.
ls -lR > dir-tree.list
# Создает файл, содержащий список дерева каталогов.
  •  : > filename # Операция > усекает файл "filename" до нулевой длины. Если до выполнения операции файла не существовало, то создается новый файл с нулевой длиной (тот же эффект дает команда 'touch'). Символ : выступает здесь в роли местозаполнителя, не выводя ничего.
  • COMMAND_OUTPUT >> Перенаправление stdout (вывода) в файл. Создает новый файл, если он отсутствовал, иначе -- дописывает в конец файла.
  • 1>filename # Перенаправление вывода (stdout) в файл "filename".
  • 1>>filename # Перенаправление вывода (stdout) в файл "filename", файл открывается в режиме добавления.
  • 2>filename # Перенаправление stderr в файл "filename".
  • 2>>filename # Перенаправление stderr в файл "filename", файл открывается в режиме добавления.
  • &>filename # Перенаправление stdout и stderr в файл "filename".

Поток ввода

  • < FILENAME # Ввод из файла. Парная команде ">", часто встречается в комбинации с ней.

Перенаправление потоков

  • 2>&1 # Перенаправляется stderr на stdout. Сообщения об ошибках передаются туда же, куда и стандартный вывод.
  • i>&j # Перенаправляется файл с дескриптором i в j. Вывод в файл с дескриптором i передается в файл с дескриптором j.
  • >&j # Перенаправляется файл с дескриптором 1 (stdout) в файл с дескриптором j. Вывод на stdout передается в файл с дескриптором j.
  • [j]<>filename # Файл "filename" открывается на чтение и запись, и связывается с дескриптором "j". Если "filename" отсутствует, то он создается. Если дескриптор "j" не указан, то, по-умолчанию, берется дескриптор 0, stdin. Как одно из применений этого -- запись в конкретную позицию в файле.
echo 1234567890 > File    # Записать строку в файл "File".
      exec 3<> File             # Открыть "File" и связать с дескриптором 3.
      read -n 4 <&3             # Прочитать 4 символа.
      echo -n . >&3             # Записать символ точки.
      exec 3>&-                 # Закрыть дескриптор 3.
      cat File                  # ==> 1234.67890
      # Произвольный доступ, да и только!

Закрытие дескрипторов файлов

  • n<&- Закрыть дескриптор входного файла n.
  • 0<&-, <&- Закрыть stdin.
  • n>&- Закрыть дескриптор выходного файла n.
  • 1>&-, >&- Закрыть stdout.

Дочерние процессы наследуют дескрипторы открытых файлов. По этой причине и работают конвейеры. Чтобы предотвратить наследование дескрипторов -- закройте их перед запуском дочернего процесса.

# В конвейер передается только stderr.
exec 3>&1                              # Сохранить текущее "состояние" stdout.
ls -l 2>&1 >&3 3>&- | grep bad 3>&-    # Закрыть дескр. 3 для 'grep' (но не для 'ls').
#              ^^^^   ^^^^
exec 3>&-                              # Теперь закрыть его для оставшейся части сценария.


Конвееры

  • | # Конвейер (канал). Универсальное средство для объединения команд в одну цепочку. Похоже на ">", но на самом деле -- более обширная. Используется для объединения команд, сценариев, файлов и программ в одну цепочку (конвейер).
cat *.txt | sort | uniq > result-file
  • Допускается перенаправление нескольких потоков в один файл.
ls -yz >> command.log 2>&1
# Сообщение о неверной опции "yz" в команде "ls" будет записано в файл "command.log".
# Поскольку stderr перенаправлен в файл.

Операции перенаправления и/или конвейеры могут комбинироваться в одной командной строке.

command < input-file > output-file
 
command1 | command2 | command3 > output-file

Генерация псевдослучайных чисел

  • $RANDOM -- внутренняя функция Bash (не константа), которая возвращает псевдослучайные целые числа в диапазоне 0 - 32767. Функция $RANDOM не должна использоваться для генераци ключей шифрования.
  • Если вам нужны случайные числа не превышающие определенного числа, воспользуйтесь оператором деления по модулю (остаток от деления).
  • Если вы желаете ограничить диапазон "снизу", то просто производите генерацию псевдослучайных чисел в цикле до тех пор, пока не получите число большее нижней границы.
#!/bin/bash
# $RANDOM возвращает различные случайные числа при каждом обращении к ней.
# Диапазон изменения: 0 - 32767 (16-битовое целое со знаком).
MAXCOUNT=10
count=1
 
echo
echo "$MAXCOUNT случайных чисел:"
echo "-----------------"
while [ "$count" -le $MAXCOUNT ]      # Генерация 10 ($MAXCOUNT) случайных чисел.
do
  number=$RANDOM
  echo $number
  let "count += 1"  # Нарастить счетчик.
done
echo "-----------------"


Завершение и код завершения

  • ...эта часть Bourne shell покрыта мраком, тем не менее все пользуются ею. Chet Ramey
  • Команда exit может использоваться для завершения работы сценария, точно так же как и в программах на языке C. Кроме того, она может возвращать некоторое значение, которое может быть проанализировано вызывающим процессом.
  • Каждая команда возвращает код завершения (иногда код завершения называют возвращаемым значением ). В случае успеха команда должна возвращать 0, а в случае ошибки -- ненулевое значение, которое, как правило, интерпретируется как код ошибки. Практически все команды и утилиты UNIX возвращают 0 в случае успешного завершения, но имеются и исключения из правил.
  • Аналогичным образом ведут себя функции, расположенные внутри сценария, и сам сценарий, возвращая код завершения. Код, возвращаемый функцией или сценарием, определяется кодом возврата последней команды. Команде exit можно явно указать код возврата, в виде: exit nnn, где nnn -- это код возврата (число в диапазоне 0 - 255).
  • Bombilla amarilla - yellow Edison lamp.pngNote : Когда работа сценария завершается командой exit без параметров, то код возврата сценария определяется кодом возврата последней исполненной командой.


Код возврата последней команды хранится в специальной переменной $?. После исполнения кода функции, переменная $? хранит код завершения последней команды, исполненной в функции. Таким способом в Bash передается "значение, возвращаемое" функцией. После завершения работы сценария, код возврата можно получить, обратившись из командной строки к переменной $?, т.е. это будет код возврата последней команды, исполненной в сценарии.

Пример. Завершение / код завершения
#!/bin/bash
 
echo hello
echo $?    # код возврата = 0, поскольку команда выполнилась успешно.
 
lskdf      # Несуществующая команда.
echo $?    # Ненулевой код возврата, поскольку команду выполнить не удалось.
 
echo
 
exit 113   # Явное указание кода возврата 113.
           # Проверить можно, если набрать в командной строке "echo $?"
           # после выполнения этого примера.
 
#  В соответствии с соглашениями, 'exit 0' указывает на успешное завершение,
#+ в то время как ненулевое значение означает ошибку.
Переменная $? особенно полезна, когда необходимо проверить результат исполнения команды (см. Пример 12-27 и Пример 12-13).

Note Символ !, может выступать как логическое "НЕ" для инверсии кода возврата.

Пример 6-2. Использование символа ! для логической инверсии кода возврата

true  # встроенная команда "true".
echo "код возврата команды \"true\" = $?"     # 0
 
! true
echo "код возврата команды \"! true\" = $?"   # 1
# Обратите внимание: символ "!" от команды необходимо отделять пробелом.
#    !true   вызовет сообщение об ошибке "command not found"

Отладка сразу всего скрипта

Когда дела идут не так, как планировалось, необходимо определить, из-за чего в скрипте возникли проблемы. В Bash для отладки предоставляются широкие возможности. Наиболее распространенным способом является запуск подоболочки с параметром -x, благодаря которому весь скрипт будет запущен в отладочном режиме. После того, как для каждой команды будут выполнены все необходимые подстановки и замены, но перед тем, как команда будет выполнена, в стандартный выходной поток будет выдана трассировка команды и все ее аргументы.

  • К примеру у нас есть скрипт
#!/bin/bash
# Данный скрипт очищает экран терминала, выдает в терминал приглашение и показывает информацию о пользователях,
# подключенных в текущий момент.  Устанавливаются значения для двух переменных, которые выдаются в терминал.
 
clear                           # очищает окно терминала
 
echo "The script starts now."
 
echo "Hi, $USER!"               # символ доллара используется для получения значения переменной
echo
 
echo "I will now fetch you a list of connected users:"
echo                                                    
w                               # показывается, кто зарегистрирован в системе
echo                            # и что каждый из них делает
 
echo "I'm setting two variables now."
COLOUR="black"                                  # устанавливает значение для переменной в локальной оболочке
VALUE="9"                                       # устанавливает значение для переменной в локальной оболочке
echo "This is a string: $COLOUR"                # показывается содержимое переменной 
echo "And this is a number: $VALUE"             # показывается содержимое переменной 
echo
 
echo "I'm giving you back your prompt now."
echo
  • Запустим его с аргументами отладки
bash -x script1.sh
+ clear
 
+ echo 'The script starts now.'
The script starts now.
+ echo 'Hi, willy!'
Hi, willy!
+ echo
 
+ echo 'I will now fetch you a list of connected users:'
I will now fetch you a list of connected users:
+ echo
 
+ w
  4:50pm  up 18 days,  6:49,  4 users,  load average: 0.58, 0.62, 0.40
 
USER     TTY      FROM              LOGIN@   IDLE   JCPU   PCPU  WHAT
root     tty2     -                Sat 2pm  5:36m  0.24s  0.05s  -bash
willy    :0       -                Sat 2pm   ?     0.00s   ?     -
willy    pts/3    -                Sat 2pm 43:13  36.82s 36.82s  BitchX willy ir
willy    pts/2    -                Sat 2pm 43:13   0.13s  0.06s  /usr/bin/screen
+ echo
 
+ echo 'I'\''m setting two variables now.'
I'm setting two variables now.
+ COLOUR=black
+ VALUE=9
+ echo 'This is a string: '
This is a string:
+ echo 'And this is a number: '
And this is a number:
+ echo
 
+ echo 'I'\''m giving you back your prompt now.'
I'm giving you back your prompt now.
+ echo


Отладка скрипта по частям

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

#!/bin/bash -xv 
set -x                  # activate debugging from here
w
set +x                  # stop debugging from here

Выдаваемая информация будет выглядеть следующим образом:

The script starts now.
Hi, willy!
 
I will now fetch you a list of connected users:
 
+ w
  5:00pm  up 18 days,  7:00,  4 users,  load average: 0.79, 0.39, 0.33
USER     TTY      FROM              LOGIN@   IDLE   JCPU   PCPU  WHAT
root     tty2     -                Sat 2pm  5:47m  0.24s  0.05s  -bash
willy    :0       -                Sat 2pm   ?     0.00s   ?     -
willy    pts/3    -                Sat 2pm 54:02  36.88s 36.88s  BitchX willyke
willy    pts/2    -                Sat 2pm 54:02   0.13s  0.06s  /usr/bin/screen
+ set +x
 
I'm setting two variables now.
This is a string:
And this is a number:
 
I'm giving you back your prompt now.
  • В одном и том же скрипте вы можете включать и выключать отладочный режим столько раз, сколько это необходимо.
set -f  (set -o noglob)  Отключается генерация имени файла с помощью метасимволов (подстановка).
set -v  (set -o verbose) Командная оболочка печатает входные строки сразу, как они считываются.
set -x  (set -o xtrace)  Перед исполнением команды выдаются трассировочные данные.
  • Bombilla amarilla - yellow Edison lamp.pngСимвол "тире" используется для активации параметра командной оболочки, а символ "плюс" - для его деактивации. Не перепутайте это!
  • Кроме того, эти режимы можно указать в самом скрипте, для этого добавьте соответствующие параметры в первую строку, в которой указывается командная оболочка. Параметры можно объединить, что является обычным приемом при использовании команд UNIX:
#!/bin/bash -xv
  • Как только вы обнаружили ошибочный фрагмент в вашем скрипте, вы можете добавить инструкции echo перед каждой командой, в работе которой вы не уверены, и можете увидеть, где именно и почему что-то не работает.
echo "debug message: now attempting to start w command"; w
  • В более сложных скриптах инструкцию echo можно добавлять для отображения значений переменных на различных этапах работы скрипта, что может помочь в обнаружении проблемы:
echo "Variable VARNAME is now set to $VARNAME."