Перейти к содержанию

Снова Баш.

На прошлой неделе мы взаимодействовали с Башем как с REPL'ом, то есть вводили команду, нажимали Enter и получали результат. На этой неделе мы будем работать с Башем, как с языком программирования и научимся писать скрипты (сценарии), чтобы автоматизировать что-либо, а также изучим основные конструкции в программировании, такие как условия, циклы, переменные.

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

Сначала пару абзацев про полезные штуки, которые называются alias'ы и поиск по истории команд.

Ты уже знаешь, что стрелочками вверх-вниз можно возвращать команды, которые были введены ранее и таким образом не вводить их снова. Но есть ещё более быстрые способы запуска частых команд.

Один из них — создание алиасов. Ты просто даешь длинной команде короткое название и пользуешься им. Например, чтобы подключаться к серверу, мы вводили ssh username@hostname, довольно много символов.

Попробуй выполнить следующую команду(только замени username на свой логин):

alias s="ssh username@hostname"

Теперь просто выполни команду s. Эта команда выполнит подключение. Удобно, не правда ли? Таким образом, можно назначить алиасы на все часто используемые команды. Например, git pushgp и экономить нажатия.

Правда тут есть один нюанс. Назначенные таким образом алиасы пропадут после перезапуска сессии. Чтобы этого не произошло, нужно их сохранить в файл ~/.bash_profile и применить изменения:

echo 'alias gp="git push"' >> ~/.bash_profile
. ~/.bash_profile

Чтобы посмотреть список всех алиасов, набери команду alias.

Вторая полезная штука — это поиск по истории команд. Нажми Ctrl+R и начни вводить команду. Тут я думаю и так всё понятно.

Ввод-вывод

Окей, теперь напишем первый скрипт. Подключись к удаленному серверу и выполняй примеры на нём.

Команды вводятся построчно, новая строка — новая команда. Можно вводить в одну строку, если разделять точкой с запятой, но так делать не надо.

Выводить информацию на экран можно с помощью команды echo:

Создай файл hello со следующим содержимым:

#!/bin/bash
#
# Скрипт поприветствует целый мир три раза

echo 'Hello World'
echo 'Hello World'
echo 'Hello World'

Сохрани его. Давай посмотрим, что тут у нас.

Первая строка начинается с конструкции шебанг (#!), шебанг сообщает системе, через что запустить скрипт, в данном случае мы указали путь до Баша, поэтому скрипт будет вызван в Баше.

Дальше, на второй и третьей строке находится символ решетки (#). Это комментарии. Всё, что дальше на строке после символа решетки, это просто текст, который никак не выполняется. Комментарии используются для пояснений и когда нужно временно отключить какой-то участок кода, чтобы он не выполнялся.

Давай теперь запустим этот скрипт. Нужно дать ему права на выполнение: chmod +x hello и выполнить: ./hello

А теперь шок-контент! Сейчас ты узнаешь, как создавать свои собственные команды, такие как cat, pwd или ls.

Все эти команды хранятся в директориях, перечисленных в переменной окружения $PATH, можешь заглянуть внутрь и убедиться: echo $PATH. Создай собственную директорию bin в своей домашней директории: mkdir ~/bin, затем открой уже знакомый файл .bash_profile и добавь в него строку export PATH="${PATH}:~/bin". Файл .bash_profile автоматически исполняется каждый раз, когда ты подключаешься к серверу, и эта команда будет добавлять к глобальному $PATH твою личную директорию bin, таким образом мы сможешь вызывать эти скрипты откуда угодно. Переподключить к серверу. Посмотри ещё раз в $PATH, теперь там появилось ~/bin. Что это значит? А то, что теперь ты можешь поместить свой скрипт в эту директорию и запускать его откуда угодно как команду!

Перенеси туда hello и попробуй вызвать его как команду hello, при этом находясь где-то за пределами директории.

Давай теперь усовершенствуем скрипт и научим его приветствовать по имени, которое будет передаваться ему на вход.

Переменные

Убедись, что ты на сервере и открой в Nano файл ~/bin/hello:

#!/bin/bash

my_var="yes"

echo "Первый параметр: $1"
echo "Второй параметр: $2"
echo "Третий параметр: $3"
echo "Всего передано параметров: $#"
echo "Имя скрипта: $0"
echo "Значение переменной my_var: $my_var"

Запусти скрипт. Попробуй догадаться, что здесь происходит.

Запусти скрипт с параметрами, например: ~/bin/hello one two

Передай ему 1, 2 или 3 параметра, посмотри как меняется вывод.

Ввод данных

Можно запросить у пользователя ввод данных и записать их в переменную, это делает команда read. Скрипт, который приветствует тебя по имени:

echo "Как тебя зовут?"
read MYNAME
echo "Привет, $MYNAME!"

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

Условия

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

if <условие>
then
    <если условие верно, то выполняется этот блок>
else
    <если условие не верно, то выполняется этот блок>
fi

Блок с else необязательный, его можно не использовать, если нам не нужно ничего делать в случае, если условие не выполняется.

Например, вот:

if cd $1
then
    echo 'так так так посмотрим шо тут у нас'
    ls -la
else
    echo 'доступ видимо закрыт'
fi

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

Ещё можно тестировать файлы в скрипте с помощью [ ... ], например, здесь мы проверяем, что переданное аргументом имя файла существует:

if [ -e $1 ]
then
    echo $1 существует
fi

Здесь можно найти все опции: https://shellmagic.xyz

Отступы здесь используются чисто для удобства.

Практика

Основное задание

Представь себе, что я заказчик и скидываю тебе примерное ТЗ (техническое задание) на выполнение. Я очень люблю удалять и часто случайно удаляю что-то не то, поэтому мне нужна команда, которая бы позволяла "безопасно" удалять файлы и директории, чтобы, если я спохватился, мог вернуть всё обратно. Я плохо понимаю в этих ваших линуксах, поэтому не могу четко сформулировать требования. По этой же причине мне нужна четкая инструкция по установке и описанию принципа работы этой команды, которая должна быть оформлена в репозитории.

Что нужно сделать

Реализовать команду srm (safe rm) для безопасного удаление файлов. Команда работает как обычный rm, то есть получает на вход путь до файла, но вместо удаления сжимает его утилитой gzip и перемещает в директорию ~/RECYCLE (корзина), в свою очередь из RECYCLE автоматически удаляются файлы, которые находятся там больше семи дней. Удаление старых файлов должно активироваться после каждого вызова srm.

Как к этому подходить

Создай пустой репозиторий с пустым файлом README.md (см предыдущий урок), для этого нужно просто нажать соответствующую галочку при создании

После создания, сделай новую ветку от мастера, можешь назвать её develop и работай в ней

Раздели задачу на подзадачи и фиксируй выполнение каждой подзадачи коммитом. Например, сначала твой скрипт проверяет, существует ли директория ~/RECYCLE, и если нет, то создаёт её — это первая подзадача, и так далее. Не забывай про правила оформления коммитов, это важно

Как всё будет готово, оформи README.md с подробным описанием работы команды и, самое главное, установкой (чтобы заказчик мог её установить на свою систему)

После того, как всё будет готово, открывай пулл реквест на слияние ветки в мастер (инструкция есть в прошлом уроке). Удачи!

Задание* (со звёздочкой)

Реализовать команду для записи заметок в блокнот прямо внутри командной строки. Представь, что ты делаешь задания на курсе и не можешь отвлекаться, тебе в голову пришла какая-то очень крутая мысль и ты хочешь моментально её записать, чтобы не забыть. Записал не покидаю терминала и работаешь дальше. Красота!

Должно быть два режима — 1) ввод коротких (однострочных) заметок прямо на вход команде, в виде аргумента. 2) ввод длинных (многострочных) заметок, которые читают пользовательский ввод и ждут символа конца файла (нажатия Ctrl+D).

Файл заметок ~/NOTES

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

Дополнительная практика

Задание 1

Скрипт для запуска гуся, на вход имя гуся! Если аргумент не передается, то остается дефолтное значение "РАБОТЯГИ", если передается имя, то оно заменяет дефолтное значение.

Шаблон:

ЗАПУСКАЕМ 
░ГУСЯ░▄▀▀▀▄░РАБОТЯГИ░░ 
▄███▀░◐░░░▌░░░░░░░ 
░░░░▌░░░░░▐░░░░░░░ 
░░░░▐░░░░░▐░░░░░░░ 
░░░░▌░░░░░▐▄▄░░░░░ 
░░░░▌░░░░▄▀▒▒▀▀▀▀▄ 
░░░▐░░░░▐▒▒▒▒▒▒▒▒▀▀▄ 
░░░▐░░░░▐▄▒▒▒▒▒▒▒▒▒▒▀▄ 
░░░░▀▄░░░░▀▄▒▒▒▒▒▒▒▒▒▒▀▄ 
░░░░░░▀▄▄▄▄▄█▄▄▄▄▄▄▄▄▄▄▄▀▄ 
░░░░░░░░░░░▌▌▌▌░░░░░ 
░░░░░░░░░░░▌▌░▌▌░░░░░ 
░░░░░░░░░▄▄▌▌▄▌▌░░░░░

Задание 2

Скрипт принимает на вход текст, выводит его задом-наперед.

Задание 3

Скрипт, который находит в твоей домашней директории (и всех вложенных директориях) все файлы, которые весят больше 1 мегабайта. Вывод должен быть таким, чтобы его можно было передать дальше команде rm и эти файлы удалились бы.

Задание 4

Скрипт вызывает команду last и выдает топ-5 студентов, которые провели больше всех времени на сервере.

Задание 5

Скрипт считывает ~/.bash_history и выдает 10 твоих самых часто используемых команд и количество использований.