Translate

Поиск по этому блогу

среда, 9 мая 2018 г.

Конспект по Bash.

Если вы работаете в ИТ, то как никто знаете о цене времени. Оптимизация рабочего процесса - один из важнейших аспектов работы в ИТ.
Так или иначе, наша работа (будь то верстка сайта, написание модулей, или тестирования приложений) требует повторения одних и тех же действий: быстрые скриншоты с загрузкой на сервер, обработка выделенного текста, конвертация файлов, парсинг данных и многое другое. Чтобы не делать лишних действий, а сконцентрироваться на идее и самой сути ее реализации, еще в 1978 году Стивен Борн разработал командную оболочку [sh] [wiki-sh], которая впоследствии, в 1987 году была усовершенствована Брайаном Фоксом и переросла в то, что мы знаем сегодня как [bash] [wiki-bash] (Bourne again shell).



Вполне логично, что появляется вопрос: "Для чего мне нужно что-то, что написали почти полвека назад?" Так вот ответ на него прост: это "что-то" до сих пор является самым мощным инструментом автоматизации и, де-факто, стандартом для написания простых, но эффективных сценариев на всех unix-based системах. Именно поэтому знать общий синтаксис bash и уметь писать на нем - критический скилл для разработчика.

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

Оболочки и вызов сценариев

Пользовательская оболочка bash может работать в двух режимах - интерактивном и, соответственно, неинтерактивном. Открыть оболочку в Ubuntu можно комбинацией клавиш Ctrl + Alt + F1, привычный графический интерфейс исчезнет, а перед вами откроется один из семи виртуальных терминалов, доступных в дистрибутиве Ubuntu. Если оболочка выдает приглашение (что-то вроде того, которое можно увидеть ниже), то вы работаете в интерактивном режиме:


    user@host:~$



Здесь можно вводить самые разнообразные unix-команды (как то: ls, grep, cd, mkdir, rm) и видеть результат их выполнения. Интерактивной эта оболочка называется потому, что она взаимодействует с пользователем направления. Окружение рабочего стола (графический интерфейс), в семействе систем Debian (к которым относится и Ubuntu), принято размещать в седьмом виртуальном терминале, для того чтобы вернуться к привычному окружение рабочего стола наберите комбинацию Ctrl + Alt + F7. Конечно работать в виртуальных терминалах не слишком удобно, особенно, если нужно редактировать документ и одновременно выполнять какие-либо команды, поэтому в дальнейшем мы будем пользоваться встроенным в графический интерфейс эмулятором виртуального терминала, встроенным в Ubuntu. Открыть его можно комбинацией клавиш Ctrl + Alt + T, или Unity Dash, найдя его в списке программ.

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


    sh скрипт
    bash скрипт



Где скрипт это путь к файлу, содержащему команды для выполнения. Такой файл является обычным текстовым документом, который можно создать с помощью любого текстового документа. Впрочем, можно упростить вызов скрипта всего лишь сделав его исполняемым. Для этого необходимо предоставить соответствующие права доступа этому файлу с помощью команды chmod:


    chmod +x скрипт



Кроме этого, в первой строке скрипта необходимо указать которая оболочка должна выполнять этот сценарий. Это можно сделать, разместив в начале соответствующее указание #! / Bin / sh (для оболочки sh) или #! / Bin / bash (соответственно для bash). После этого файл можно будет вызвать на выполнение обратившись к нему в терминале:


    ./скрипт



Комментарии

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


    #!/bin/bash
    # Сценарий, выведет имя пользователя
    whoami



Переменные

Оболочка позволяет создавать и удалять переменные, а также выполнять над ними операции. Переменные в bash могут находиться в 3-х областях видимости:

Локальные переменные - это обычные переменные в внутри одного сценария. Они не доступны другим программам и сценариям, которые запускаются с этой оболочки. Объявляются переменные с помощью символа = (обратите внимание на то, что перед и после = нет пробелов), а с их значением обращаются с помощью символа $:


    name="Петро Петрович"
    echo $name    # вывод значения
    unset name    # удаление переменной



Также можно сказать локальную переменную внутри функции и которая будет доступна только в теле этой функции:


    localлокальная_переменная=значение



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


    exportглобальная_переменная=значение



В bash есть много переменных окружения, которые достаточно часто встречаются в сценариях, например:
  • > HOME - путь к домашнему каталогу пользователя;
  • > PATH - список каталогов, в которых оболочка ищет исполняемые файлы;
  • > PWD - путь к рабочему каталогу;
  • > RANDOM - формирует целое случайное число;
  • > HOSTNAME - имя компьютера, на котором выполняется оболочка;
  • >


Переменные оболочки - это переменные, которые устанавливаются оболочкой и необходимые ей для корректной работы. Эти переменные имеют имена порядкового номера ($ 1, $ 2, $ 3, ...) и содержат аргументы, которые передавались сценария при запуске, как:


    ./some_script.sh VAL1 VAL2  # внутри сценария $1='VAL1', $2='VAL2' 



Переменным можно присваивать значения по умолчанию следующим образом:


    : ${VAR:='значення за замовчуванням'} # Если переменная VAR пуста, присвоить ей "значение по умолчанию"



Массивы и списки

В bash также есть возможность работать с массивами. При работе с массивами часто пользуются переменной окружения IFS - разделителя полей для входных строк (IFS - Input Field Separator). По умолчанию IFS равный Пробельные символа, но может быть изменен для разбиения строки на элементы массива, например, запятыми. Обратите внимание, что для формирования переменных оболочки, которые доступны через $ 1, $ 2 и т.д., используется именно переменная IFS, то есть введен после имени скрипта строку аргументов, будет разделен именно с первым символом, который хранится в этой переменной.

Объявить массив можно следующим образом:


    files[0]=Яблоко
    files[1]=Груша
    echo ${files[*]}    # напечатает элементы массива без учета IFS
    echo ${files[@]}    # напечатает элементы массива с IFS в качестве разделителя.



Доступ к элементу массива можно с помощью срезов: $ {arr: 0: 1}. Удалить первый элемент массива можно с помощью сдвига: shift arr. Добавить в элементы в массив: arr = ("$ {arr [@]}" "Item 1" "Item 2"). Проверить вхождения элемента в массив реализуется с помощью несколько более сложной конструкции:


    if [[ ${arr[(r)some]} == some ]]; then
         # команды, если элемент входит
    else
         # команды, если не входит
    fi



В этом примере arr - некоторый массив, а some - это элемент, который мы проверяем на вхождение.

Подстановки результатов операций.

Присвоить переменной результат работы команды или арифметических операций можно с помощью апострофов, или конструкции $ (выражение):


    now=`data +%T`
    # або
    now=$(data +%T)

    echo now # 19:08:26



Арифметические операции необходимо накладывать в двойные скобки:

   
    foo=$(( ((10 + 5*3) – 7) / 2 ))
    echo $foo    #> 9



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


    echo beg{i,a,u}n #> begin began begun



Стоит вспомнить и о строгости кавычек в bash: одинарные кавычки - строгие, двойные - нестрогие. Это означает, что при подстановке переменных в строку с двойными кавычками, интерпретатор подставит соответствующее значение переменной. Одинарные кавычки выведут строку так, как вы его написали. пример:


    echo "Домашняя директория: $HOME"  #> Домашняя директория: /home/user
    echo 'Домашняя директория: $HOME'  #> Домашняя директория: $HOME



Потоки.

Файл с которого происходит чтение, называют стандартным потоком ввода, а в какой происходит запись, соответственно - стандартным потоком вывода. В bash есть три стандартных потока:

 
    0  stdin   ввод         
    1  stdout  выводд        
    2  stderr  поток ошибок



Для перенаправления потоков используют основные операторы:
  • > - перенаправления потока вывода в файл (файл будет создан, или перезаписан)
  • >> - дописать поток вывода в конец файла;
  • < - перенаправляет данные из файла в поток ввода;
  • <<< - чтение данных из строки, вместо всего содержимого файла (работает для bash 3+)
  • 2> - перенаправляет поток ошибок в файл (файл будет создан, или перезаписан)
  • 2>> - дописать ошибки в конец файла; тадада


Kаналы

Стандартные потоки можно перенаправить не только в файлы, но и на вход других сценариям. Соединение потока вывода одной программы с потоком ввода другой называют каналом или пайпом (pipe). Ниже приведен простой конвейер из трех команд: команда1 перенаправляет свой вывод на вход команды2, которая, в свою очередь, перенаправляет собственный вывод на вход команды3:


  cmd1 | cmd2 | cmd3



Kонвейеры

Конвейеры - это команды, которые соединены операторами ; , && , || для выполнения в определенной последовательности. Операторы организации конвейеров работают следующим образом:
  • > команда1; команда2 - команда2 исполнится после команды1 независимо от результата ее работы команды1;
  • > команда1 && команда2 - команда2 выполнятся только после успешного выполнения команды1 (т.е. с кодом завершения 0);
  • > команда1 || команда2 - команда2 исполнится только после неудачного выполнения команды1 (то есть код завершения команды1 будет отличным от 0)


Условные операторы

В скриптовом языке bash поддерживаются два оператора ветвления: if и case. Оператор if, как и в других языках, выполняет определенный блок указаний, в зависимости от условия. Условие окутывают в двойные квадратные скобки [[...]], которые bash рассматривает как один элемент с кодом выхода. Внутри блока операторов накрытого в [[ ]] разрешается использовать операторы && и ||. примеры:


   # однострочная запись
   if [ ... ]; then echo "true"; else echo "false"; fi;

   ## вложенные условия
   if [ ... ] && [ ... ]; then
        ...
   elif [[ ... && ... ]]; then
        ...
   else
        ...
   fi;



Обратите внимание, что [, условие и] обязательно должны быть разделены пробелами, иначе оболочка воспримет в качестве команды [условие.

В ниже приведена таблица с возможными условиями сравнения:


  # Работа с файлами
  -e    Проверить существует ли файл или директория (-f, -d)
  -f    Файл существует (!-f - не существует)
  -d    Каталог существует (!-f - не существует)
  -s    Файл существует и он не пустой
  -r    Файл существует и доступен для чтения
  -w    ... для записи
  -x    ... для выполнения
  -h    Есть c символической ссылкой

  # Работа со строками
  -z    Пустая строка
  -n    Не пустая строка
  ==    Ровно
  !=    Не ровно

  # Операции с числами
  -eq   Ровно
  -ne   Не ровно
  -lt   Менше
  -le   Менше или ровно
  -gt   Больше
  -ge   Больше или ровно


все основные команды можно посмотреть здесь - Основные команды Bash

примеры:


    if [ `uname` == "Adam"]; then
    echo "Не їж яблуко!"
elif [ `uname` == "Eva"] then
    echo "Не бери яблуко!"
else
    echo "Яблука зараз дуже дорогі!"
fi;



Если необходимо сделать выбор из нескольких альтернатив, пригодится оператор case. Принцип его работы легче понять на примере:


 case "$extension" in
    (jpg|jpeg)
        echo "Це зображення у форматі jpeg."
    ;;
    png)
        echo "Це зображення у форматі png"
    ;;
    gif)
         echo "А це гіфочка))"
    *)
        echo "Оу! Це взагалі не зображення!"
    ;;
 esac


В примере оператор проверяет значение переменной $ extension на совпадение с одним из шаблонов и в случае совпадения выполнит соответствующий блок кода. В случае, если не будет найдено совпадений, выполнятся указания, соответствуют шаблону * .

Циклы

Язык оболочки дает пользователю возможность организовывать циклическое выполнение инструкций при помощи циклов:
  1. > while
  2. > for
  3. > select
Оператор while описывается следующим образом:


    while условие do
         тeло
    done



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


   #!/bin/sh
   # Квадраты чисел от 1 до 10
   x=0
   while [ $x –lt 10 ] do 
   #значение переменной x меньше 10?
       echo $(($x*$x))
       x=`expr $x + 1` # увеличиваем х на 1
   done



Цикл for выполняет тело для каждого элемента из списка. Синтаксис цикла for таков:


   for имя in елемент1 елемент2 ... елементN do
        тeло
   done



В качестве элементов обычно используют различные шаблоны (wildcards). Очень удобно применять for для прохождения по каталогам и выполнения операций над группой файлов. В примере ниже, цикл проходит по всем файлах с расширением * .bash, перемещает их в директорию ~ / scripts и добавляет их права на исполнение.


   #!/bin/sh
   # Перемещение всех скриптов из ~ в директорию ~/scripts
   for FILE in $HOME/*.bash do
        mv $FILE ${HOME}/scripts
        chmod +x ${HOME}/scripts/${FILE}
   done


Цикл select помогает организовать удобное меню выбора и применяется тогда, когда пользователь должен выбрать один элемент из предложенного списка. В общем цикл select имеет такой же синтаксис как и цикл for:


  select ответ in елемент1 елемент2 ... елементN do
       тіло
done



При выполнении этого оператора, все элементы из списка высвечиваются на экране со своими порядковыми номерами в виде списка вариантов ответа, после списка выводится специальное приглашение для ввода. Обычно оно имеет вид # ? . Введенный пользователем номер списка записывается в переменную ответ. Если ответ содержит номер пункта меню, то в переменную заносится значение соответствующего элемента из списка. Если в списке нет введенного пункта, список будет показан снова. После того, как пользователь сделает правильный выбор, выполнятся указания в теле, а цикл перейдет к следующей итерации и все действия повторятся с самого начала - именно поэтому работу цикла select желательно прерывать


   #!/bin/sh

   echo -n "Введите название пакета: " && read PACKAGE
   PS3="Выберите пакетный менеджер : "
   select ITEM in bower, npm, pip do
        case $ITEM in
            bower) bower install $PACKAGE ;;
            npm) npm install $PACKAGE ;;
            pip) pip install $PACKAGE ;;
        esac
        break
   done



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

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

Функции.

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


   имя_функции () {
        команды
   }

   имя_функции    # обращение к функции



Объявление функции обязательно должно предшествовать ее первом вызове. Обращение к функции происходит путем указания ее имени в качестве команды.

Функция может принимать аргументы и возвращать после своего выполнения результат - код выхода. Функция направляется в своих аргументов точно так же, как и в локальных переменных, с помощью позиционных переменных - $ 1, $ 2 и тд. Результат работы можно поворачивать с помощью команды return. Например, функция, которая принимает параметр (имя) и заканчивая свою работу с кодом 0:


   #!/bin/sh
   #функция с параметром
   greeting() {
        if [ -n "$1" ]; then
            echo "Привет, $1!"
        else
             echo "Привет, неизвестный!"
        fi
        return 0
   }

   greeting пользователь    #> Привет, пользователь!
   greeting               #> Привет, неизвестный!



Команда return возвращает код завершения 0 - это код успешного завершения сценария. Каждая программа по завершению работы записывает в переменную окружения #? код завершения - число от 0 до 255. С помощью этой переменной можно определять статус выполнения каждой отдельной команды или скрипта. Если программа завершилась ошибкой, кодом завершения будет целое число отличное от нуля. Обратите внимание, что если сценарий завершается командой exit без параметров, кодом завершения сценария будет код завершения последней выполненной команды.

Отладка сценариев.

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


   #!/bin/sh опция



Можно выбирать среди следующих функций:
  1. > -n - читать все команды, но не выполнять их;
  2. > -v - выводить все строки по мере их обработки интерпретатором;
  3. > -x - выводить все команды и их аргументы по мере их выполнения.
Для налаживания сценария частями, нужный фрагмент замечают вызовом команды set с соответствующей опцией из таблицы. Причем, для включения режима отладки, перед опцией указывают символ - для отключения режима отладки используют + .


   set –x # включаем режим  отладки
   ...
   set +x # выключаем режим  отладки



Общая практика налаживания заключается в том, чтобы прежде чем запустить его на выполнение, необходимо проверить его синтаксис с помощью опции -n . Для большей детальности можно комбинировать ключи -nv . После исправления синтаксических ошибок проводится отладка с помощью опции -x .

Послесловие.

Надеюсь вы нашли для себя что-то новое в этом конспекте, или по крайней мере освежили свои знания.

Если вас заинтересовал скриптинг на Bash, прошу поддержать меня, распространяя статью среди своих друзей.

Рад буду услышать конструктивную критику и замечания в комментариях.






Выражаю благодарность изданию codeguida за любезно предоставленный материал.

Автор: denysdovhan.
Перевод: Kolesnikov Yaroslav.                                                                                                                                                              

Комментариев нет:

Отправить комментарий



Хотите освоить самые современные методы написания React приложений? Надоели простые проекты? Нужны курсы, книги, руководства, индивидуальные занятия по React и не только? Хотите стать разработчиком полного цикла, освоить стек MERN, или вы только начинаете свой путь в программировании, и не знаете с чего начать, то пишите через форму связи, подписывайтесь на мой канал в Телеге, вступайте в группу на Facebook.Пишите мне - kolesnikovy70 почта gmail.com