Если вы активно используете Linux для администраторских задач, то наверняка заглядываете время от времени в консоль (или живёте в ней). Несмотря на активное вытеснение текстового интерфейса графическим, а тыкать галочки и нажимать на кнопочки всё-таки интуитивнее, что породило целое поколение эникейщиков, консоль была, есть и будет эффективным средством общения с компьютером. Данная статья рассчитана на тех, кто уже как бы знаком с Bash (Bourne-again Shell), самой популярной реализацией командной оболочки. Этот терминал уже много лет используется по умолчанию чуть ли не в каждом дистрибутиве Linux, так что новички даже не догадываются, что бывают и другие оболочки. Bash пронизан мудростью наших UNIX-предков и всячески рекомендуется для освоения. Сейчас вы увидите, что консоль бывает полезна не только для команд вида «sudo /etc/rc.d/network restart» :)

Псевдонимы


Трёхэтажные команды выглядят очень круто, но набирать их каждый раз утомительно. Так вот Bash позволяет создавать краткие произвольные псевдонимы любому набору команд. К примеру, можно создать команду-псевдоним «la», которая будет запускать «ls -a».

alias la='ls -a'

А чтобы при перезагрузке ваши новые настройки не потерялись, запишите псевдонимы в файл ~/.bash_aliases.

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


Всем, кто знаком хотя бы с основами программирования, знакомо понятие условных операторов типа if then else. Bash хоть и не является языком программирования, но допускает использование таких операторов, что невероятно удобно и позволяет избежать использования языков вроде Perl или Python в простых задачах. Вот например:

if uname -a | grep "GNU/Linux" > /dev/null; then echo "Вы работаете в Linux"; fi

Работает это следующим образом: сначала выполняется команда «uname -a», которая получает информацию о вашей системе. Полученная информация просеивается через фильтр «grep», который ищет в ней строку GNU/Linux. Вывод направлен в «dev/null» (чёрная дыра Линукса), потому как нас интересует факт наличия строки, а не её вывод на экран. If, then и fi, как вы уже догадались, и есть условный оператор Bash. «If» проверяет условие, «then» описывает действие, которое соответствует условию, а «fi» просто означает конец логической структуры. Условие может быть любой сложности.

Давайте рассмотрим более полезный пример и проверим запущен ли где-то в системе Firefox. Для этого используем команду «ps aux», а вывод информации перенаправим на фильтр grep. Grep сам является программой, поэтому есть в списке процессов. Поскольку «firefox» содержится в «grep firefox», то окажется, что Firefox якобы есть в процессах, хотя мы запустили всего лишь поиск этой строки. Чтобы обойти неувязочку, используем grep дважды, для фильтрации самого себя :) Запустим его с ключом -v для инвертирования условия:

if ps aux | grep firefox | grep -v grep > /dev/null; then echo "Firefox запущен"; fi

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

alias isff='if ps aux | grep firefox | grep -v grep > /dev/null; then echo "Firefox запущен"; fi'

Теперь для проверки нужно лишь выполнить команду isff.

Циклы


Истинная мощь Bash даже не в условных операторах, а в циклах. Циклы используются для многократного повторения некой операции. Рассмотрим на примере:

while (true); do sleep 1; date; done

Команда ежесекундно выводит дату и время на экран, пока не нажмут Ctrl+C. Но это как-то тупо, давайте сделаем что-то более полезное.

Как, например, распаковать несколько архивов tar.bz2 одной командой? А вот так: командой «ls» получаем список bz2-файлов в каталоге и с помощью цикла обрабатываем каждый файл по отдельности. Разумеется, в автоматическом режиме.

for i in `ls *.tar.bz2`; do tar xjf "$i"; done

Обратите внимание на символ обратного апострофа (он расположен на клавиатуре слева от цифры 1). Это оператор, который подставляет результат команды «ls *.tar.bz2» в соответствующее место цикла.

Недооценённый Grep


Обычно Grep используют для решения дебильных задач, вроде таких:

somecommand | grep "fuuu"

То есть для грубой фильтрации вереницы иформации (звучит прям как light amplification by stimulated emission of radiation). Вообще у команды grep огромное количество параметров, но вот самые основные и их стоит запомнить:

-c Подсчитывает число вхождений искомой строки.
-i Поиск, не зависящий от регистра символов.
-l Выводит на экран имена совпавших файлов (это строчная L).
-n Отображает номер соответствующей запросу строки.
-r Выполняет рекурсивный поиск по каталогам.
-v Инвертирует условие поиска (строки, не содержащие цель поиска).


Параметры можно объединять, а grep можно направлять на самого себя. Например, если необходимо подсчитать количество файлов, которые содержат слово «paul» (или «PAUL», «PaUl» и т.д.), кроме тех, которые имеют расширение .txt, вам следует сделать что-то вроде такого:

grep -ilr paul * | grep -cv "\.txt$"

Здесь мы используем важнейшие свойства grep. Комбинация параметров -ilr означает, что выполняется поиск по файлам слов «PAUL», «PaUl» и т.д., поиск проходит рекурсивно по вашей файловой системе, начиная с текущего каталога и возвращает имена подходящих файлов. Всё это поступает на ещё один экземпляр grep, который выполнятся с параметрами -cv, которые, в свою очередь, включают режим подсчёта и поиска файлов, которые не соответствуют регулярному выражению "\.txt$". Обратный слеш здесь экранирует точку, без него мы получили бы специальный символ. А знак доллара означает, что .txt должно находится в конце имени файла. То есть «fuuu.txt.boo» не будет соответствовать выражению.

Не очевидный Find


Команда find не подчиняется законам здравого смысла. То есть не думайте, что можете использовать её в виде «find <иголка> <стог_сена>». В отличие от этого, find работает как фильтр.

find .

Точка в конце означает, что будет возвращён список всех файлов в текущем каталоге. Но команда «ls -a» делает, в принципе, то же самое. Поэтому усложним задачу. Найдём файлы в каталоге, в имени которых есть «arr».

find . -name "*arr*"

А ещё можно добавить параметр "-size" и найти только те файлы, которые больше 1-го мегабайта.

find . -name "*bar*" -size +1M

Параметр "-user" возвращает файлы, принадлежащие указанному пользователю. Например:

find . -name "*bar*" -user veles

Это также полезно использовать с параметром "-not", который, как вы уже догадались, инвертирует поиск:

# все файлы, кроме myfile.txt и тех, которыми владеет veles
find . -not -name "myfile.txt" -not -user veles


Ещё один прикольный фильтр — "-newer". Он возвращает все файлы, которые новее, чем указанный файл. Это очень удобно для скриптов резервного копирования: когда делаете копию, просто укажите произвольный файл, и он будет служить временной меткой, которую можно использовать в команде «find -newer». Таким образом вы получите список всех файлов, которые изменились с момента создания этого файла.

find . -newer /path/to/myfile

Пока достаточно. Разумеется, тонны деталей упущены и остаются вам на самостоятельное изучение. «Маны» ещё никто не отменял, а цель данной статьи — привлечь ваше внимание к великому и могучему UNIX-way.

В следующий раз мы познакомимся с управлением многозадачностью (вы же не забыли, что консоль Линукса многозадачна?), а также подружимся с планировщиком cron, который может стать вашим любимым средством автоматизации рутинной работы.

P.S. Юниксоиды со стажем, скорее всего, давно всё это знают. Но эта статья написана больше для хорошего аппетита интересующихся.