Shell основы. Основы программирования в командной оболочке shell. Преимущества командной строки

Что такое shell и зачем он нужен

Командная оболочка в любых unix-подобных системах, к которым относится и GNU/Linux, является обычной программой, запускаемой как в текстовой консоли (которая используется всё реже), так и в графической среде – в окне эмулятора терминала, доступного в любой Linux-системе.

Ее задача проста и очевидна: принять строку (или строки) ввода, произвести их синтаксический анализ и на основе результатов этого анализа отреагировать соответствующим образом – выполнить команду, запустить программу, вывести диагностическое сообщение и т.п.

Почти во всех дистрибутивах Linux для пользователей по умолчанию назначается командная оболочка bash (Bourne Again SHell – ещё одна командная оболочка Бурна; Стив Бурн – автор первой командной оболочки в Unix – sh). Фактически она стала неофициальным стандартом, и усовершенствование ее функциональных возможностей продолжается непрерывно. Существуют и другие командные оболочки – tcsh (версия C-shell), ksh (Korn Shell), zsh и т.д. – у каждой есть свои достоинства и недостатки, а также свои группы поклонников. Тем не менее, bash более привычна широким массам пользователей с различными уровнями подготовки, потому я и остановил свой выбор на ней. Стоит также отметить, что какими бы возможностями ни обладали различные оболочки, все они совместимы со своим идеологическим прародителем – Bourn Shell (sh). Иными словами, скрипт, написанный для sh, будет корректно работать в любой современной оболочке (обратно, вообще говоря, неверно).

Преимущества командной строки

Может возникнуть вопрос: зачем возиться с командной строкой, если существуют удобные и красивые графические интерфейсы? Тому есть множество причин. Во-первых, далеко не все операции удобнее и быстрее выполнять с помощью графического интерфейса. Во-вторых, каждая программа следует основополагающему принципу Unix-систем: делать чётко определённую работу и делать её хорошо. Иными словами, вы всегда понимаете, что происходит при запуске той или иной утилиты (если что-то не вполне понятно, то следует обратиться к man-руководству). В-третьих, осваивая команды, пробуя их сочетания и комбинации их параметров, пользователь изучает систему, приобретая ценный практический опыт. Вы получаете доступ к таким эффективным инструментам, как конвейеры, позволяющие организовать цепочку команд для обработки данных, средства перенаправления ввода/вывода, а кроме того, можете программировать непосредственно в командной оболочке. Пожалуй, на программировании стоит остановиться подробнее, тем более что многие системные сценарии в Linux (например, скрипты запуска системных сервисов) написаны для shell.

Командная оболочка в качестве языка программирования

Итак, командную оболочку можно рассматривать как язык программирования и как программную среду выполнения одновременно. Разумеется, этот язык не компилируемый, а интерпретируемый. Он допускает использование переменных: системных или собственных. Последовательность выполнения команд программы изменяется с помощью конструкций проверки условия и выбора соответствующего варианта: if-then-else и case. Циклы while, until и for позволяют автоматизировать многократно повторяющиеся действия. Имеется возможность объединять группы команд в логические блоки. Вы можете даже писать настоящие функции с передачей в них параметров. Таким образом, налицо все признаки и характеристики полноценного языка программирования. Попробуем извлечь из этого двойную пользу – наряду с изучением основ программирования автоматизируем свою повседневную работу.

Hello, World! Простая система резервного копирования

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

#!/bin/bash # # Резервное копирование каталогов и файлов из домашнего каталога # Этот командный скрипт можно автоматически запускать при помощи cron # cd $HOME if [ ! -d archives ] then mkdir archives fi cur_date=`date +%Y%m%d%H%M` if [ $# -eq 0 ] ; then tar czf archive${cur_date}.tar.gz projects bin else tar czf archive${cur_date}.tar.gz $* fi if [ $? = 0 ] ; then mv archive${cur_date}.tar.gz $HOME/archives echo "$cur_date – Резервное копирование успешно завершено." else echo "$cur_date – ОШИБКА во время резервного копирования." fi

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

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

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

Наконец-то мы добрались до первой «настоящей» команды. Она позволяет сменить каталог (Change Directory), т.е. перейти из текущего каталога в другой, переданный команде как аргумент. В большинстве случаев целевой каталог задаётся в явной форме, например, cd /tmp или cd projects, но в нашем случае используется предопределённая системная переменная HOME – в ней содержится полный путь к домашнему каталогу текущего пользователя, от имени которого выполняется командный сценарий. Тем самым мы избавляемся от необходимости вносить изменения в код всякий раз при смене пользователя, потому что команда возвращает любого в его личный каталог. Знак доллара "$" перед именем переменной означает, что необходимо извлечь значение, содержащееся в этой переменной, и подставить его в командную строку вместо её имени. Особо следует отметить, что в командном языке оболочки регистров букв имеют важное значение, т.е. HOME, Home и home – это три различные переменные. По соглашению, буквами верхнего регистра обозначаются имена системных переменных: HOME, PATH, EDITOR и т.д. Это соглашение не запрещает пользователям создавать свои переменные с именами из заглавных букв, но зачем усложнять себе жизнь, нарушая общепринятые нормы и правила? Не рекомендуется также изменять значения системных переменных без крайней необходимости. В общем, соблюдаем простое правило: системные переменные используем только для чтения, а если потребовалась собственная, то её имя записываем буквами нижнего регистра.

Нашу первую команду можно было бы записать более кратко:

cd ~

Здесь символ "~" также означает домашний каталог текущего пользователя. Ветераны командной строки выражаются ещё лаконичнее:

cd

Смысл в том, что когда для команды cd не задан никакой аргумент, она выполняет переход в домашний каталог.

На очереди классическая программная конструкция проверки условия и принятия соответствующего решения. Общая схема такова:

if <условие> then <одна или несколько команд> fi

Последнее слово конструкции (if в обратном порядке) выполняет роль закрывающей скобки, т.е. границы списка команд, выполняемых при истинности условия. Присутствие fi обязательно, даже если в списке лишь одна команда.

Для проверки условия, как правило, применяется команда test или её альтернативная форма записи в квадратных скобках. Иначе говоря, записи

if [ ! -d archives ] if test ! -d archives

абсолютно равнозначны. Я предпочитаю квадратные скобки, поскольку они более наглядно определяют границы проверяемого условия. И правая, и левая скобка должны быть обязательно отделены от условия пробелами.

Критерии проверки условия определяются разнообразными флагами. Команда test распознаёт очень большой их список. В нашем примере использован флаг -d, позволяющий проверить, соответствует ли заданное после флага имя реально существующему каталогу (directory). Наиболее часто при работе с файлами применяются следующие флаги:

F – существует ли обычный файл с заданным именем;

R – установлено ли для заданного файла право на чтение из него;

W – установлено ли для заданного файла право на запись в него;

X – установлено ли для заданного файла право на его выполнение;

S – имеет ли заданный файл ненулевой размер.

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

if [ ! -d archives ] Если не существует каталог archives (в текущем каталоге), then то начать выполнение блока команд: mkdir archives создать каталог archives (в текущем каталоге) fi завершить выполнение блока команд.

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

В следующей строке мы создаём собственную локальную переменную cur_date. В подавляющем большинстве случаев переменные создаются простым присваиванием конкретного значения, например:

ten=10 string="Это строка текста"

Но в нашем примере применяется небольшая хитрость. Обратите внимание, что после знака равенства – символа присваивания – записана команда в обратных кавычках. Такая форма записи позволяет присвоить переменной не саму строку, а результат её выполнения. Здесь это вывод команды date, которая возвращает текущую дату и время в формате, определяемом списком параметров:

%Y – текущий год в полной форме, т.е. из четырёх цифр (например, 2009);

%m – номер текущего месяца (например, 09 – для сентября);

%d – номер текущего дня;

%H – текущий час в 24-часовом формате;

%M – текущая минута.

Таким образом, если выполнить команду

cur_date=`date +%Y%m%d%H%M`

десятого сентября 2009 года в 22:45, то переменной cur_date будет присвоено строковое значение "200909102245". Цель этого ухищрения – сформировать уникальное, не повторяющееся имя архивного файла. Если вы намерены запустить несколько экземпляров программы в течение одной минуты, то можете улучшить уникальность имён, добавляя ещё и текущие секунды. Как? Изучите руководство утилиты date (man date) – в этом нет ничего сложного.

Прежде чем приступить к созданию файла архива, необходимо определить, какие именно каталоги мы будем сохранять в нём. Для большей гибкости можно задать набор каталогов, архивируемых по умолчанию, но предусмотреть возможность замены этого набора списком каталогов, передаваемым как аргумент в наш командный сценарий. Для этого используются специальные переменные командной оболочки: $# – число переданных в сценарий параметров и $* – все переданные параметры, записанные в формате одной строки.

if [ $# -eq 0 ] ; then

Проверка условия «если число переданных параметров равно нулю», то выполнить следующую команду. Отметим, что ключевое слово then можно записать в строке условия, отделив его от условного выражения точкой с запятой.

tar czf archive${cur_date}.tar.gz projects bin

Команда создания архивного файла и сжатия этого файла. Сама утилита tar не выполняет сжатие, а только лишь собирает все заданные файлы и каталоги в единый tar-файл. Для этого предназначен первый флаг - c (create – создать). Сжатие выполняет внешняя программа – здесь это gzip, вызываемый вторым флагом - z. Если в вашей системе установлена более эффективная программа сжатия bzip2, то вы можете воспользоваться ею, изменив команду следующим образом:

tar cjf archive${cur_date}.tar.bz2 projects bin

Третий флаг f сообщает о том, что далее следует имя архивного файла, поэтому всегда является замыкающим в перечне флагов. Обратите внимание на то, что при подстановке имя переменной заключено в фигурные скобки. Это сделано, чтобы явно выделить переменную в окружающей её строке, тем самым устраняя многие потенциальные проблемы. Расширения архивному файлу не присваиваются автоматически, вы сами дописываете всё необходимое. В качестве каталогов, архивируемых по умолчанию, я указал projects и bin, но вы можете записать здесь имена своих наиболее ценных каталогов.

Ключевое слово else открывает альтернативную ветвь выполнения. Команды этого блока начинают работать, если проверка условия даёт результат «ложь» (в нашем примере: «число переданных параметров ненулевое», т.е. пользователь задал имена каталогов). В этом случае команда будет выглядеть так:

tar czf archive${cur_date}.tar.gz $*

Здесь каталоги по умолчанию заменены строкой имён каталогов, принятой извне. Имеется возможность принимать и обрабатывать каждый внешний параметр по отдельности, но нам удобнее передать строку целиком.

В конце программы выполняется ещё одна проверка. В unix-средах все команды возвращают код статуса завершения своей работы. Если команда отработала успешно, то она возвращает код 0, в противном случае код завершения будет ненулевым. Чтобы проверить успешность выполнения предыдущей команды архивации, воспользуемся ещё одной специальной переменной $?, в которой всегда содержится значение кода завершения самой последней команды. Если в переменной $? содержится 0, т.е. файл резервной копии был успешно создан, то мы перемещаем его в каталог архивов:

mv archive${cur_date}.tar.gz $HOME/archives

и выдаём соответствующее сообщение:

echo "$cur_date – Резервное копирование успешно завершено."

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

echo "$cur_date – ОШИБКА во время резервного копирования."

На этом работа нашего командного сценария завершается.

Чтобы проверить работу нашей программы, необходимо сохранить описанный выше исходный код в файле, например, с именем bckp, а затем для удобства сделать его выполняемым:

chmod 750 bckp

и запустить:

./bckp

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

./bckp docs progs works

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

Можно поместить файл bckp в один из каталогов, указанных в системной переменной PATH. Наиболее предпочтительными местами размещения являются /usr/local/bin или $HOME/bin, если таковые у вас имеются. После этого вы можете запускать bckp как системную команду.

Как автоматизировать операции резервного копирования «по расписанию»

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

crontab -e

Инструкции записываются в строго определённом формате (поля разделяются пробелами):

минуты часы день_месяца месяц день_недели команда

Один из вариантов расписания операций резервного копирования может выглядеть следующим образом:

30 23 10,20,30 * * /usr/local/bin/bckp

Это означает, что сценарий резервного копирования (следует указать полный путь к этому файлу) будет выполняться в 23:30 10-го, 20-го и 30-го числа каждого месяца независимо от дня недели. (Звёздочки обозначают весь допустимый диапазон значений, в данном случае: каждый месяц – в 4-м поле, любой день недели – в 5-м поле)

Если вы предпочитаете подводить итоги по неделям, а ваша система работает круглосуточно, то имеет смысл запланировать резервное копирование в часы с минимальной нагрузкой:

0 5 * * 3,5 /usr/local/bin/bckp

Здесь резервные копии будут создаваться в 5:00 по средам и пятницам в каждом месяце (звёздочка в 4-м поле), независимо от числа (звёздочка в 3-м поле).

Обо всех тонкостях составления расписания можно прочитать в руководстве man 5 crontab.

Итоги и выводы

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

Ресурсы для скачивания

static.content.url=http://www.сайт/developerworks/js/artrating/

ArticleID=458335

ArticleTitle=Основы программирования в командной оболочке shell

  • Tutorial

Зачем и для кого статья?

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

Здесь не будет пересказа манов (документации), и статья никак не отменяет и не заменяет их чтение. Вместо этого я расскажу о главных вещах (командах, приемах и принципах), которые надо осознать с самого начала работы в unix shell-е, чтобы работа происходила эффективно и приятно.

Статья касается полноценных unix-подобных окружений, с полнофункциональным шеллом (предпочтительно zsh или bash)и достаточно широким набором стандартных программ.

Что такое шелл

Shell (шелл, он же «командная строка», он же CLI, он же «консоль», он же «терминал», он же «черное окошко с белыми буковками») -- это текстовый интерфейс общения с операционной системой (ну, строго говря, это программа , которая таковой интерфейс обеспечивает, но сейчас это различие несущественно).

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

Типичный вид шелла:

Шелл - это основной способ для взаимодействия со всеми Unix-подобными серверными системами.

Где встречаются системы с командной строкой?

Где вас может поджидать unix-овый шелл, популярные варианты:
  • MacOS (bash);
  • удаленный доступ на сервер по работе или для личного веб-проекта;
  • домашний файл-сервер с удаленным доступом;
  • Ubuntu, PC-BSD на ноутбуке/десктопе - unix-подобные системы сегодня просты в установке и использовании.

Какие задачи разумно решать шеллом?

Естественные задачи, для которых шелл пригоден, полезен и незаменим:
  • интерактивная работа в терминале:
    • выполнение компиляции, запуск заданий через make;
    • сравнение текстовых файлов;
    • быстрый ad-hoc анализ данных (количество уникальных ip в логе, распределение записей по часам/минутам и т.п.);
    • разовые массовые действия (прибить много процессов; если работаете с системой контроля версий - ревертнуть или зарезолвить кучу файлов);
    • диагностика происходящего в системе (семафоры, локи, процессы, дескрипторы, место на диске и т.п.);
  • скриптование:
    • установочные скрипты, для выполнения которых нельзя рассчитывать на наличие других интерпретаторов - это не для новичков;
    • функции для кастомизации интерактивного шелла (влияющие на приглашение, меняющие каталог, устанавливающие переменные окружения) - тоже не совсем для новичков;
    • одноразовые скрипты типа массового перекодирования файлов;
    • makefile-ы.

Абсолютно первые шаги

Начинаем работу: войти и выйти

Убедитесь, что точно знаете, как запустить шелл и как из него выйти.

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

На MacOS - тоже запустить Terminal.

Для доступа к удаленному серверу - воспользоваться ssh (если локально у вас MacOS, Ubuntu или другая unix-like система) или putty (если у вас Windows).

Кто я, где я?

Выполните следующие команды:
  • hostname - выводит имя машины (сервера), на которой вы сейчас находитесь;
  • whoami - выводит ваш логин (ваше имя в системе);
  • tree -d / |less - псевдографическое изображение дерева каталогов на машине; выход из пролистывания - q ;
  • pwd - выводит каталог, в котором вы сейчас находитесь; в командной строке вы не можете быть «просто так», вы обязательно находитесь в каком-то каталоге (=текущий каталог, рабочий каталог). Вероятно, текущий рабочий каталог выводится у вас в приглашении (prompt).
  • ls - список файлов в текущем каталоге; ls /home - список файлов в указанном каталоге;

История команд (history)

Важное свойство полноценной командной строки - история команд.

Выполните несколько команд: hostname , ls , pwd , whoami . Теперь нажмите клавишу «вверх». В строке ввода появилась предыдущая команда. Клавишами «вверх» и «вниз» можно перемещаться вперед и назад по истории. Когда долистаете до hostname , нажмите Enter - команда выполнится еще раз.

Команды из истории можно не просто выполнять повторно, а еще и редактировать. Долистайте историю до команды ls , добавьте к ней ключ -l (получилось ls -l , перед минусом пробел есть, а после - нет). Нажмите Enter - выполнится модифицированная команда.

Пролистывание истории, редактирование и повторное выполнение команд - самые типичные действия при работе в командной строке, привыкайте.

Copy-paste

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

Прекрасной особенностью текста является то, что его можно копировать и вставлять, это верно и для командной строки.

Попробуйте выполнить команду date +"%y-%m-%d, %A"
Вводили ли вы ее целиком руками или скопировали из статьи? Убедитесь, что вы можете ее скопировать, вставить в терминал и выполнить.

После того, как научитесь пользоваться man "ом, убедитесь, что можете скопировать и выполнить примеры команд из справки. Для проверки найдите в справке по программе date раздел EXAMPLES , скопируйте и выполните первый приведенный пример (на всякий случай: знак доллара не является частью команды, это условное изображение приглашения к вводу).

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

Ключи и опции

При исследовании истории команд вы уже столкнулись с тем, что у команды ls есть по крайней мере два варианта. Если вызвать ее просто так, она выводит простой список:

Akira@latitude-e7240: ~/shell-survival-quide> ls Makefile shell-first-steps.md shell-first-steps.pdf shell-survival-quide.md shell-survival-quide.pdf
Если же добавить ключ -l , к каждому файлу выводится подробная информация:

Akira@latitude-e7240: ~/shell-survival-quide> ls -l total 332 -rw-rw-r-- 1 akira akira 198 Feb 13 11:48 Makefile -rw-rw-r-- 1 akira akira 15107 Feb 14 22:26 shell-first-steps.md -rw-rw-r-- 1 akira akira 146226 Feb 13 11:49 shell-first-steps.pdf -rw-rw-r-- 1 akira akira 16626 Feb 13 11:45 shell-survival-quide.md -rw-rw-r-- 1 akira akira 146203 Feb 13 11:35 shell-survival-quide.pdf
Это очень типичная ситуация: если к вызову команды добавлять специальные модификаторы (ключи, опции, параметры), поведение команды меняется. Сравните: tree / и tree -d / , hostname и hostname -f .

Кроме того, команды могут принимать в качестве параметров имена файлов, каталогов или просто текстовые строки. Попробуйте:

Ls -ld /home ls -l /home grep root /etc/passwd

man

man - справка по командам и программам, доступным на вашей машине, а также по системным вызовам и стандартной библиотеке C.

Попробуйте: man grep , man atoi , man chdir , man man .

Пролистывание вперед и назад делается кнопками «вверх», «вниз», «PageUp», «PageDown», выход из просмотра справки - кнопкой q . Поиск определенного текста в справочной статье: нажимите / (прямой слеш), введите текст для поиска, нажимите Enter. Перемещение к следующим вхождениям - клавиша n .

Все справочные статьи делятся на категории. Самые важные:

  • 1 - исполняемые программы и шелльные команды (wc , ls , pwd и т.п.);
  • 2 - системные вызовы (fork , dup2 и т.п.)
  • 3 - библиотечные функции (printf , scanf , cos , exec).
Указывать, из какой именно категории надо показать справку, нужно в случаях совпадений имен. Например, man 3 printf описывает функцию из стандартной библиотеки C, а man 1 printf - консольную программу с таким же именем.

Посмотреть список всех доступных на машине справочных статей можно с помощью команды man -k . (точка - тоже часть комады).

less

Когда в небольшом окне терминала надо просмотреть очень длинный текст (содержимое какого-то файла, длинный man и т.п.), используют специальные программы-«пейджеры» (от слова page/страница, то есть постраничные листатели). Самый популярный листатель - less , и именно он обеспечивает вам пролистывание, когда вы читаете man-ы.

Попробуйте и сравните поведение:

Cat /etc/bash.bashrc cat /etc/bash.bashrc |less

Можно передать файл в пролистыватель сразу в параметрах:

Less /etc/bash.bashrc

Пролистывание вверхи и вниз - кнопки «вверх», «вниз», «PageUp», «PageDown», выход - кнопка q . Поиск определенного текста: нажимите / (прямой слеш), введите текст для поиска, нажимите Enter. Перемещение к следующим вхождениям - клавиша n . (Узнаете инструкцию про man ? Ничего удивительного, для вывода справки тоже используется less .)

Права

С любым файлом или каталогом связан набор «прав»: право на чтение файла, право на запись в файл, право исполнять файл. Все пользователи делятся на три категории: владелец файла, группа владельца файла, все прочие пользователи.

Посмотреть права на файл можно с помощью ls -l . Например:

> ls -l Makefile -rw-r--r-- 1 akira students 198 Feb 13 11:48 Makefile
Этот вывод означает, что владельцу (akira) можно читать и писать файл, группе (students) - только читать, всем прочим пользователя - тоже только читать.

Если при работе вы получаете сообщение permission denied , это значит, что у вас недостаточно правна объект, с которым вы хотели работать.

Подробнее читайте в man chmod .

STDIN, STDOUT, конвейеры (пайпы)

С каждой исполняющейся программой связаны 3 стандартных потока данных: поток входных данных STDIN , поток выходных данных STDOUT , поток для вывода ошибок STDERR .

Запустите программу wc , введите текст Good day today , нажмите Enter, введтие текст good day , нажмите Enter, нажмите Ctrl+d. Программа wc покажет статистику по количеству букв, слов и строк в вашем тексте и завершится:

> wc good day today good day 2 5 24
В данном случае вы подали в STDIN программы двухстрочный текст, а в STDOUT получили три числа.

Теперь запустите команду head -n3 /etc/passwd , должно получиться примерно так:

> head -n3 /etc/passwd root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin
В этом случае программа head ничего не читала из STDIN , а в STDOUT написала три строки.

Можно представить себе так: программа - это труба, в которую втекает STDIN , а вытекает STDOUT .

Важнейшее свойство юниксовой командной строки состоит в том, что программы-«трубы» можно соединять между собой: выход (STDOUT) одной программы передавать в качестве входных данных (STDIN) другой программе.

Такая конструкция из соединенных программ называется по-английски pipe (труба), по-русски - конвейер или пайп.

Объединение программ в конвейер делается символом | (вертикальная черта)

Выполните команду head -n3 /etc/passwd |wc , получится примерно следующее:

> head -n3 /etc/passwd |wc 3 3 117
Произошло вот что: программа head выдала в STDOUT три строки текста, которые сразу же попали на вход программе wc , которая в свою очередь подсчитала количество символов, слов и строк в полученном тексте.

В конвейер можно объединять сколько угодно программ. Например, можно добавить к предыдущему конвейеру еще одну программу wc , которая подсчитает, сколько слов и букв было в выводе первой wc:

> head -n3 /etc/passwd |wc |wc 1 3 24

Составление конвейеров (пайпов) - очень частое дело при работе в командной строке. Пример того, как это делается на практике, читайте в разделе «Составление конвейера-однострочника».

Перенаправление ввода-вывода

Вывод (STDOUT) програмы можно не только передать другой программе по конвейеру, но и просто записать в файл. Такое перенаправление делается с помощью > (знак «больше»):

Date > /tmp/today.txt
В результате выполнения этой команды на диске появится файл /tmp/today.txt . Посмотрите его содержимое с помощью cat /tmp/today.txt

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

Если надо не перезаписать файл, а добавить вывод в его конец, используйте >> :

Date >> /tmp/today.txt
Проверьте, что теперь записано в файле.

Кроме того, программе можно вместо STDIN передать любой файл. Попробуйте:

Wc

Что делать, когда что-то непонятно

Если вы сталкиваетесь с поведением системы, которое не понимаете, или хотите добиться определенного результата, но не знаете, как именно, советую действовать в следующем порядке (кстати, это относится не только к шеллам):
  • насколько возможно четко сформулируйте вопрос или задачу - нет ничего сложнее, чем решать «то, не знаю что»;
  • вспомните, сталкивались ли вы уже с такой же или подобной проблемой - в этом случае стоит попробовать решение, которое сработало в прошлый раз;
  • почитайте подходящие man-ы (если понимаете, какие man-ы подходят в вашем случае) - возможно, вы найдете подходящие примеры использования команд, нужные опции или ссылки на другие команды;
  • подумайте: нельзя ли немного поменять задачу? - возможно, чуть-чуть изменив условия, вы получите задачу, которую уже умеете решать;
  • задайте свой четко сформулированный вопрос в поисковой системе - возможно, ответ найдется на Stack Overflow или других сайтах;
Если ничего из перечисленного не помогло - обратитесь за советом к преподавателю, опытному коллеге или товарищу. И не бойтесь задавать «глупые» вопросы - не стыдно не знать, стыдно не спрашивать.

Если вы разобрались со сложной проблемой (самостоятельно, с помощью Интернета или других людей) -- запишите свое решение на случай, если такая же проблема снова возникнет у вас или ваших товарищей. Записывать можно в простой текстовый файл, в Evernote, публиковать в соц.сетях.

Методы работы

Скопировать-и-вставить - из man-ов, из статей на StackOverflow и т.п.Командная строка состоит из текста, пользуйтесь этим: копируйте и используйте примеры команд,записывайте удачные находки на память, публикуйте их в твиттерах и блогах.

Вытащить из истории предыдущую команду, добавить в конвейер еще одну команду, запустить, повторить .См. также раздел «Составление конвейера-однострочника».

Базовые команды

  • переход в другой каталог: cd ;
  • просмотр содержимого файлов: саt , less , head , tail ;
  • манипуляции с файлами: cp , mv , rm ;
  • просмотр содержимого каталогов: ls , ls -l , ls -lS ;
  • структура каталогов: tree , tree -d (можно передать в качестве параметра каталог);
  • поиск файлов: find . -name ... ;

Аналитика

  • wc , wc -l ;
  • sort -k - сортировка по указанному полю;
  • sort -n - числовая соритровка;
  • diff - сравнение файлов;
  • grep , grep -v , grep -w , grep "\" , grep -E - поиск текста;
  • uniq , uniq -c - уникализация строк;
  • awk - в варианте awk "{print $1}" , чтобы оставить только первое поле из каждой строки, $1 можно менять на $2 , $3 и т.д.;

Диагностика системы

  • ps axuww - информация о процессах (запущенных программах), работающих на машине;
  • top - интерактивный просмотр самых ресурсоемких процессов;
  • df - занятое и свободное место на диске;
  • du - суммарный размер файлов в каталоге (рекурсивно с подкаталогами);
  • strace , ktrace - какие системные вызовы выполняет процесс;
  • lsof - какие файлы использует процесс;
  • netstat -na , netstat -nap - какие порты и сокеты открыты в системе.

Некоторых программ у вас может не быть, их надо установить дополнительно. Кроме того, некоторые опции этих программ доступны только привилегированным пользователям (root "у).

Массовое и полуавтоматическое выполнение

На первых порах пропускайте этот раздел, эти команды и конструкции понадобятся вам тогда, когда доберетесь до несложного шелльного скриптинга.
  • test - проврека условий;
  • while read - цикл по строчкам STDIN ;
  • xargs - подстановка строк из STDIN в параметры указанной программе;
  • seq - генерация последовательностей натуральных чисел;
  • () - объединить вывод нескольких команд;
  • ; - выполнить одно за другим;
  • && - выполнить при условии успешного завершения первой команды;
  • || - выполнить при условии неудачного завершения первой команды;
  • tee - продублировать вывод программы в STDOUT и в файл на диске.

Разное

  • date - текущая дата;
  • curl - скачивает документ по указаному url и пишет результат на STDOUT ;
  • touch - обновить дату модификации файла;
  • kill - послать процессу сигнал;
  • true - ничего не делает, возвращает истину, полезна для организации вечных циклов;
  • sudo - выполнить команду от имени root "а.

Составление конвейера-однострочника

Давайте рассмотрим пример реальной задачи: требуется прибить все процессы task-6-server , запущенные от имени текущего пользователя.

Шаг 1.
Понять, какая программа выдает примерно нужные данные, хотя бы и не в чистом виде. Для нашей задачи стоит получить список всех процессов в системе: ps axuww . Запустить.

Шаг 2.
Посмотреть на полученные данные глазами, придумать фильтр, который выкинет часть ненужных данных. Часто это grep или grep -v . Клавишей «Вверх» вытащить из истории предыдущую команду, приписать к ней придуманный фильтр, запустить.

Ps axuww |grep `whoami`
- только процессы текущего пользователя.

Шаг 3.
Повторять пункт 2, пока не получатся чистые нужные данные.

"
- все процессы с нужным именем (плюс, может быть, лишние вроде vim task-6-server.c и т.п.),

Ps axuww |grep `whoami` | grep "\" | grep -v vim ps axuww |grep `whoami` | grep "\" | grep -v vim |grep -v less
- только процессы с нужным именем

Ps axuww |grep `whoami` | grep "\" | grep -v vim |grep -v less |awk "{print $2}"

Pid-ы нужных процессов, п. 3 выполнен

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

  • |wc -l чтобы посчитать количество процессов;
  • >pids чтобы записать pid-ы в файл;
  • |xargs kill -9 убить процессы.

Задания для тренировки

Хотите попрактиковаться в новых умениях? Попробуйте выполнить следующие задания:
  • получите список всех файлов и каталогов в вашем домашнем каталоге;
  • получите список всех man -статей из категории 2 (системные вызовы);
  • посчитайте, сколько раз в man-е по программе grep встречается слово grep;
  • посчитайте, сколько процессов запущено в данный момент от имени пользователя root ;
  • найдите, какая команда встречается в максимальном количестве категорий справки (man);
  • подсчитайте, сколько раз встречается слово var на странице ya.ru .
Подсказка: вам понадобится find , grep -o , awk "{print $1}" , регулярные выражения в grep , curl -s .

Что изучать дальше?

Если командная строка начинает вам нравиться, не останавливайтесь, продолжайте совершенствовать свои навыки.

Вот некоторые программы, которые определенно вам пригодятся, если вы будете жить в командной строке:

  • find со сложными опциями
  • apropos
  • locate
  • telnet
  • netcat
  • tcpdump
  • rsync
  • screen
  • zgrep , zless
  • visudo
  • crontab -e
  • sendmail
Кроме того, со временем стоит освоить какой-нибудь скриптовый язык,например, perl или python , или даже их оба.

Кому это надо?

А стоит ли вообще изучать сегодня командную строку и шелльный скриптинг? Определенно стоит. Приведу только несколько примеров из требований Facebook к кандидатам, которые хотят поступить на работу в FB.
  • Tutorial

Зачем и для кого статья?

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

Здесь не будет пересказа манов (документации), и статья никак не отменяет и не заменяет их чтение. Вместо этого я расскажу о главных вещах (командах, приемах и принципах), которые надо осознать с самого начала работы в unix shell-е, чтобы работа происходила эффективно и приятно.

Статья касается полноценных unix-подобных окружений, с полнофункциональным шеллом (предпочтительно zsh или bash)и достаточно широким набором стандартных программ.

Что такое шелл

Shell (шелл, он же «командная строка», он же CLI, он же «консоль», он же «терминал», он же «черное окошко с белыми буковками») -- это текстовый интерфейс общения с операционной системой (ну, строго говря, это программа , которая таковой интерфейс обеспечивает, но сейчас это различие несущественно).

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

Типичный вид шелла:

Шелл - это основной способ для взаимодействия со всеми Unix-подобными серверными системами.

Где встречаются системы с командной строкой?

Где вас может поджидать unix-овый шелл, популярные варианты:
  • MacOS (bash);
  • удаленный доступ на сервер по работе или для личного веб-проекта;
  • домашний файл-сервер с удаленным доступом;
  • Ubuntu, PC-BSD на ноутбуке/десктопе - unix-подобные системы сегодня просты в установке и использовании.

Какие задачи разумно решать шеллом?

Естественные задачи, для которых шелл пригоден, полезен и незаменим:
  • интерактивная работа в терминале:
    • выполнение компиляции, запуск заданий через make;
    • сравнение текстовых файлов;
    • быстрый ad-hoc анализ данных (количество уникальных ip в логе, распределение записей по часам/минутам и т.п.);
    • разовые массовые действия (прибить много процессов; если работаете с системой контроля версий - ревертнуть или зарезолвить кучу файлов);
    • диагностика происходящего в системе (семафоры, локи, процессы, дескрипторы, место на диске и т.п.);
  • скриптование:
    • установочные скрипты, для выполнения которых нельзя рассчитывать на наличие других интерпретаторов - это не для новичков;
    • функции для кастомизации интерактивного шелла (влияющие на приглашение, меняющие каталог, устанавливающие переменные окружения) - тоже не совсем для новичков;
    • одноразовые скрипты типа массового перекодирования файлов;
    • makefile-ы.

Абсолютно первые шаги

Начинаем работу: войти и выйти

Убедитесь, что точно знаете, как запустить шелл и как из него выйти.

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

На MacOS - тоже запустить Terminal.

Для доступа к удаленному серверу - воспользоваться ssh (если локально у вас MacOS, Ubuntu или другая unix-like система) или putty (если у вас Windows).

Кто я, где я?

Выполните следующие команды:
  • hostname - выводит имя машины (сервера), на которой вы сейчас находитесь;
  • whoami - выводит ваш логин (ваше имя в системе);
  • tree -d / |less - псевдографическое изображение дерева каталогов на машине; выход из пролистывания - q ;
  • pwd - выводит каталог, в котором вы сейчас находитесь; в командной строке вы не можете быть «просто так», вы обязательно находитесь в каком-то каталоге (=текущий каталог, рабочий каталог). Вероятно, текущий рабочий каталог выводится у вас в приглашении (prompt).
  • ls - список файлов в текущем каталоге; ls /home - список файлов в указанном каталоге;

История команд (history)

Важное свойство полноценной командной строки - история команд.

Выполните несколько команд: hostname , ls , pwd , whoami . Теперь нажмите клавишу «вверх». В строке ввода появилась предыдущая команда. Клавишами «вверх» и «вниз» можно перемещаться вперед и назад по истории. Когда долистаете до hostname , нажмите Enter - команда выполнится еще раз.

Команды из истории можно не просто выполнять повторно, а еще и редактировать. Долистайте историю до команды ls , добавьте к ней ключ -l (получилось ls -l , перед минусом пробел есть, а после - нет). Нажмите Enter - выполнится модифицированная команда.

Пролистывание истории, редактирование и повторное выполнение команд - самые типичные действия при работе в командной строке, привыкайте.

Copy-paste

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

Прекрасной особенностью текста является то, что его можно копировать и вставлять, это верно и для командной строки.

Попробуйте выполнить команду date +"%y-%m-%d, %A"
Вводили ли вы ее целиком руками или скопировали из статьи? Убедитесь, что вы можете ее скопировать, вставить в терминал и выполнить.

После того, как научитесь пользоваться man "ом, убедитесь, что можете скопировать и выполнить примеры команд из справки. Для проверки найдите в справке по программе date раздел EXAMPLES , скопируйте и выполните первый приведенный пример (на всякий случай: знак доллара не является частью команды, это условное изображение приглашения к вводу).

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

Ключи и опции

При исследовании истории команд вы уже столкнулись с тем, что у команды ls есть по крайней мере два варианта. Если вызвать ее просто так, она выводит простой список:

Akira@latitude-e7240: ~/shell-survival-quide> ls Makefile shell-first-steps.md shell-first-steps.pdf shell-survival-quide.md shell-survival-quide.pdf
Если же добавить ключ -l , к каждому файлу выводится подробная информация:

Akira@latitude-e7240: ~/shell-survival-quide> ls -l total 332 -rw-rw-r-- 1 akira akira 198 Feb 13 11:48 Makefile -rw-rw-r-- 1 akira akira 15107 Feb 14 22:26 shell-first-steps.md -rw-rw-r-- 1 akira akira 146226 Feb 13 11:49 shell-first-steps.pdf -rw-rw-r-- 1 akira akira 16626 Feb 13 11:45 shell-survival-quide.md -rw-rw-r-- 1 akira akira 146203 Feb 13 11:35 shell-survival-quide.pdf
Это очень типичная ситуация: если к вызову команды добавлять специальные модификаторы (ключи, опции, параметры), поведение команды меняется. Сравните: tree / и tree -d / , hostname и hostname -f .

Кроме того, команды могут принимать в качестве параметров имена файлов, каталогов или просто текстовые строки. Попробуйте:

Ls -ld /home ls -l /home grep root /etc/passwd

man

man - справка по командам и программам, доступным на вашей машине, а также по системным вызовам и стандартной библиотеке C.

Попробуйте: man grep , man atoi , man chdir , man man .

Пролистывание вперед и назад делается кнопками «вверх», «вниз», «PageUp», «PageDown», выход из просмотра справки - кнопкой q . Поиск определенного текста в справочной статье: нажимите / (прямой слеш), введите текст для поиска, нажимите Enter. Перемещение к следующим вхождениям - клавиша n .

Все справочные статьи делятся на категории. Самые важные:

  • 1 - исполняемые программы и шелльные команды (wc , ls , pwd и т.п.);
  • 2 - системные вызовы (fork , dup2 и т.п.)
  • 3 - библиотечные функции (printf , scanf , cos , exec).
Указывать, из какой именно категории надо показать справку, нужно в случаях совпадений имен. Например, man 3 printf описывает функцию из стандартной библиотеки C, а man 1 printf - консольную программу с таким же именем.

Посмотреть список всех доступных на машине справочных статей можно с помощью команды man -k . (точка - тоже часть комады).

less

Когда в небольшом окне терминала надо просмотреть очень длинный текст (содержимое какого-то файла, длинный man и т.п.), используют специальные программы-«пейджеры» (от слова page/страница, то есть постраничные листатели). Самый популярный листатель - less , и именно он обеспечивает вам пролистывание, когда вы читаете man-ы.

Попробуйте и сравните поведение:

Cat /etc/bash.bashrc cat /etc/bash.bashrc |less

Можно передать файл в пролистыватель сразу в параметрах:

Less /etc/bash.bashrc

Пролистывание вверхи и вниз - кнопки «вверх», «вниз», «PageUp», «PageDown», выход - кнопка q . Поиск определенного текста: нажимите / (прямой слеш), введите текст для поиска, нажимите Enter. Перемещение к следующим вхождениям - клавиша n . (Узнаете инструкцию про man ? Ничего удивительного, для вывода справки тоже используется less .)

Права

С любым файлом или каталогом связан набор «прав»: право на чтение файла, право на запись в файл, право исполнять файл. Все пользователи делятся на три категории: владелец файла, группа владельца файла, все прочие пользователи.

Посмотреть права на файл можно с помощью ls -l . Например:

> ls -l Makefile -rw-r--r-- 1 akira students 198 Feb 13 11:48 Makefile
Этот вывод означает, что владельцу (akira) можно читать и писать файл, группе (students) - только читать, всем прочим пользователя - тоже только читать.

Если при работе вы получаете сообщение permission denied , это значит, что у вас недостаточно правна объект, с которым вы хотели работать.

Подробнее читайте в man chmod .

STDIN, STDOUT, конвейеры (пайпы)

С каждой исполняющейся программой связаны 3 стандартных потока данных: поток входных данных STDIN , поток выходных данных STDOUT , поток для вывода ошибок STDERR .

Запустите программу wc , введите текст Good day today , нажмите Enter, введтие текст good day , нажмите Enter, нажмите Ctrl+d. Программа wc покажет статистику по количеству букв, слов и строк в вашем тексте и завершится:

> wc good day today good day 2 5 24
В данном случае вы подали в STDIN программы двухстрочный текст, а в STDOUT получили три числа.

Теперь запустите команду head -n3 /etc/passwd , должно получиться примерно так:

> head -n3 /etc/passwd root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin
В этом случае программа head ничего не читала из STDIN , а в STDOUT написала три строки.

Можно представить себе так: программа - это труба, в которую втекает STDIN , а вытекает STDOUT .

Важнейшее свойство юниксовой командной строки состоит в том, что программы-«трубы» можно соединять между собой: выход (STDOUT) одной программы передавать в качестве входных данных (STDIN) другой программе.

Такая конструкция из соединенных программ называется по-английски pipe (труба), по-русски - конвейер или пайп.

Объединение программ в конвейер делается символом | (вертикальная черта)

Выполните команду head -n3 /etc/passwd |wc , получится примерно следующее:

> head -n3 /etc/passwd |wc 3 3 117
Произошло вот что: программа head выдала в STDOUT три строки текста, которые сразу же попали на вход программе wc , которая в свою очередь подсчитала количество символов, слов и строк в полученном тексте.

В конвейер можно объединять сколько угодно программ. Например, можно добавить к предыдущему конвейеру еще одну программу wc , которая подсчитает, сколько слов и букв было в выводе первой wc:

> head -n3 /etc/passwd |wc |wc 1 3 24

Составление конвейеров (пайпов) - очень частое дело при работе в командной строке. Пример того, как это делается на практике, читайте в разделе «Составление конвейера-однострочника».

Перенаправление ввода-вывода

Вывод (STDOUT) програмы можно не только передать другой программе по конвейеру, но и просто записать в файл. Такое перенаправление делается с помощью > (знак «больше»):

Date > /tmp/today.txt
В результате выполнения этой команды на диске появится файл /tmp/today.txt . Посмотрите его содержимое с помощью cat /tmp/today.txt

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

Если надо не перезаписать файл, а добавить вывод в его конец, используйте >> :

Date >> /tmp/today.txt
Проверьте, что теперь записано в файле.

Кроме того, программе можно вместо STDIN передать любой файл. Попробуйте:

Wc

Что делать, когда что-то непонятно

Если вы сталкиваетесь с поведением системы, которое не понимаете, или хотите добиться определенного результата, но не знаете, как именно, советую действовать в следующем порядке (кстати, это относится не только к шеллам):
  • насколько возможно четко сформулируйте вопрос или задачу - нет ничего сложнее, чем решать «то, не знаю что»;
  • вспомните, сталкивались ли вы уже с такой же или подобной проблемой - в этом случае стоит попробовать решение, которое сработало в прошлый раз;
  • почитайте подходящие man-ы (если понимаете, какие man-ы подходят в вашем случае) - возможно, вы найдете подходящие примеры использования команд, нужные опции или ссылки на другие команды;
  • подумайте: нельзя ли немного поменять задачу? - возможно, чуть-чуть изменив условия, вы получите задачу, которую уже умеете решать;
  • задайте свой четко сформулированный вопрос в поисковой системе - возможно, ответ найдется на Stack Overflow или других сайтах;
Если ничего из перечисленного не помогло - обратитесь за советом к преподавателю, опытному коллеге или товарищу. И не бойтесь задавать «глупые» вопросы - не стыдно не знать, стыдно не спрашивать.

Если вы разобрались со сложной проблемой (самостоятельно, с помощью Интернета или других людей) -- запишите свое решение на случай, если такая же проблема снова возникнет у вас или ваших товарищей. Записывать можно в простой текстовый файл, в Evernote, публиковать в соц.сетях.

Методы работы

Скопировать-и-вставить - из man-ов, из статей на StackOverflow и т.п.Командная строка состоит из текста, пользуйтесь этим: копируйте и используйте примеры команд,записывайте удачные находки на память, публикуйте их в твиттерах и блогах.

Вытащить из истории предыдущую команду, добавить в конвейер еще одну команду, запустить, повторить .См. также раздел «Составление конвейера-однострочника».

Базовые команды

  • переход в другой каталог: cd ;
  • просмотр содержимого файлов: саt , less , head , tail ;
  • манипуляции с файлами: cp , mv , rm ;
  • просмотр содержимого каталогов: ls , ls -l , ls -lS ;
  • структура каталогов: tree , tree -d (можно передать в качестве параметра каталог);
  • поиск файлов: find . -name ... ;

Аналитика

  • wc , wc -l ;
  • sort -k - сортировка по указанному полю;
  • sort -n - числовая соритровка;
  • diff - сравнение файлов;
  • grep , grep -v , grep -w , grep "\" , grep -E - поиск текста;
  • uniq , uniq -c - уникализация строк;
  • awk - в варианте awk "{print $1}" , чтобы оставить только первое поле из каждой строки, $1 можно менять на $2 , $3 и т.д.;

Диагностика системы

  • ps axuww - информация о процессах (запущенных программах), работающих на машине;
  • top - интерактивный просмотр самых ресурсоемких процессов;
  • df - занятое и свободное место на диске;
  • du - суммарный размер файлов в каталоге (рекурсивно с подкаталогами);
  • strace , ktrace - какие системные вызовы выполняет процесс;
  • lsof - какие файлы использует процесс;
  • netstat -na , netstat -nap - какие порты и сокеты открыты в системе.

Некоторых программ у вас может не быть, их надо установить дополнительно. Кроме того, некоторые опции этих программ доступны только привилегированным пользователям (root "у).

Массовое и полуавтоматическое выполнение

На первых порах пропускайте этот раздел, эти команды и конструкции понадобятся вам тогда, когда доберетесь до несложного шелльного скриптинга.
  • test - проврека условий;
  • while read - цикл по строчкам STDIN ;
  • xargs - подстановка строк из STDIN в параметры указанной программе;
  • seq - генерация последовательностей натуральных чисел;
  • () - объединить вывод нескольких команд;
  • ; - выполнить одно за другим;
  • && - выполнить при условии успешного завершения первой команды;
  • || - выполнить при условии неудачного завершения первой команды;
  • tee - продублировать вывод программы в STDOUT и в файл на диске.

Разное

  • date - текущая дата;
  • curl - скачивает документ по указаному url и пишет результат на STDOUT ;
  • touch - обновить дату модификации файла;
  • kill - послать процессу сигнал;
  • true - ничего не делает, возвращает истину, полезна для организации вечных циклов;
  • sudo - выполнить команду от имени root "а.

Составление конвейера-однострочника

Давайте рассмотрим пример реальной задачи: требуется прибить все процессы task-6-server , запущенные от имени текущего пользователя.

Шаг 1.
Понять, какая программа выдает примерно нужные данные, хотя бы и не в чистом виде. Для нашей задачи стоит получить список всех процессов в системе: ps axuww . Запустить.

Шаг 2.
Посмотреть на полученные данные глазами, придумать фильтр, который выкинет часть ненужных данных. Часто это grep или grep -v . Клавишей «Вверх» вытащить из истории предыдущую команду, приписать к ней придуманный фильтр, запустить.

Ps axuww |grep `whoami`
- только процессы текущего пользователя.

Шаг 3.
Повторять пункт 2, пока не получатся чистые нужные данные.

"
- все процессы с нужным именем (плюс, может быть, лишние вроде vim task-6-server.c и т.п.),

Ps axuww |grep `whoami` | grep "\" | grep -v vim ps axuww |grep `whoami` | grep "\" | grep -v vim |grep -v less
- только процессы с нужным именем

Ps axuww |grep `whoami` | grep "\" | grep -v vim |grep -v less |awk "{print $2}"

Pid-ы нужных процессов, п. 3 выполнен

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

  • |wc -l чтобы посчитать количество процессов;
  • >pids чтобы записать pid-ы в файл;
  • |xargs kill -9 убить процессы.

Задания для тренировки

Хотите попрактиковаться в новых умениях? Попробуйте выполнить следующие задания:
  • получите список всех файлов и каталогов в вашем домашнем каталоге;
  • получите список всех man -статей из категории 2 (системные вызовы);
  • посчитайте, сколько раз в man-е по программе grep встречается слово grep;
  • посчитайте, сколько процессов запущено в данный момент от имени пользователя root ;
  • найдите, какая команда встречается в максимальном количестве категорий справки (man);
  • подсчитайте, сколько раз встречается слово var на странице ya.ru .
Подсказка: вам понадобится find , grep -o , awk "{print $1}" , регулярные выражения в grep , curl -s .

Что изучать дальше?

Если командная строка начинает вам нравиться, не останавливайтесь, продолжайте совершенствовать свои навыки.

Вот некоторые программы, которые определенно вам пригодятся, если вы будете жить в командной строке:

  • find со сложными опциями
  • apropos
  • locate
  • telnet
  • netcat
  • tcpdump
  • rsync
  • screen
  • zgrep , zless
  • visudo
  • crontab -e
  • sendmail
Кроме того, со временем стоит освоить какой-нибудь скриптовый язык,например, perl или python , или даже их оба.

Кому это надо?

А стоит ли вообще изучать сегодня командную строку и шелльный скриптинг? Определенно стоит. Приведу только несколько примеров из требований Facebook к кандидатам, которые хотят поступить на работу в FB.

Любой универсальной ОС приходится много возиться с пользовательскими и своими собственными задачами. Лишь небольшая часть этой деятельности может быть запрограммирована раз и навсегда в ядре. Большая часть логики управления задачами и самой системой должна быть доступна администратору в виде проекта, иначе он просто не сможет ни понять происходящее в системе, ни тем более изменять ее. Стоит повнимательнее взглянуть на инструмент, используемый в UNIX для задания алгоритма работы многих частей системы, - на командный интерпретатор , shell . Оказывается, shell отлично себя показывает не только в диалоге с пользователем, но и как исполнитель сценариев , и как средство организации взаимодействия между задачами в системе.

Начнем с того, что shell - полноценный язык программирования , причем, как многие интерпретаторы, довольно высокого уровня. Если задача - разовая (нет требований по быстродействию, совместимости и переносимости) и достаточно абстрактная (нет привязки к конкретной сложной структуре данных), ее скорее всего можно решить, написав командный сценарий - программу на shell .

С другой стороны, одной алгоритмической полнотой при решении задач в системе ограничиваться нельзя. Скажем, машина Тьюринга [ 9 ] чрезвычайно проста и алгоритмически полна, однако мало кому придет в голову организовывать на основе ее модели диалог с пользователем или управление самой ОС. Здесь следует вспомнить, что shell - еще и исполнитель команд: он запросто общается с UNIX и утилитами. Значит, дополнив его механизмом управляемого взаимодействия команд с системой и друг с другом, мы получим неплохой интегратор (или оболочку - что, собственно, и есть перевод слова shell ).

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

Сценарий

Прежде чем рассмотреть возможности shell под двумя углами зрения, разрешим вот какое затруднение. Допустим, мы написали программу на языке какого-нибудь интерпретатора, например /bin/sh , и записали ее в некий файл , например /home/george/myscript (если /home/george - текущий каталог , можно использовать более короткий путь : myscript ). Как теперь выполнить этот сценарий ? Из man sh мы знаем, что для этого можно запустить командный интерпретатор с параметром - именем файла:

$ cat myscript echo "Hello, George!" $ /bin/sh myscript Hello, George!

Нельзя ли обойтись без имени программы, которая интерпретирует сценарий ? Вообще говоря, нет: в UNIX немало различных интерпретаторов с разнообразным синтаксисом, например обработчик текстов awk , потоковый текстовый редактор sed , универсальные языки программирования python и perl и много чего еще. Во всех этих языках есть возможность вставлять в текст сценария строчные комментарии, которые начинаются с символа "#" и заканчиваются в конце строки. Поэтому, если сценарий начинается с символов " # !", любой из этих интерпретаторов проигнорирует всю первую строку как комментарий. Система же, увидев " # !" в начале файла, понимает, что это сценарий . С третьего символа и до конца строки она читает имя программы , которой отдает этот файл на выполнение. Значит, если первой строкой в /home/george/myscript будет #!/bin/sh , его смело можно делать исполняемым (установить бит использования) и запускать:

$ chmod +x myscript $ cat myscript #!/bin/sh echo "Hello, $1!" $ ./myscript George Hello, George!

Строго говоря, после " # !" может стоять что угодно, например имя написанной нами программы с некоторыми обязательными параметрами; UNIX ее запустит и передаст ей в качестве параметров командной строки обязательные параметры (если они есть), затем имя сценария и все, что идет следом (в нашем примере George ). Если же после " # !" будет стоять несуществующий файл , система выдаст сообщение об ошибке :

$ cat myscript #!/bad/sh echo "Hello, $1!" $ ./myscript ./myscript: not found

Обратите, пожалуйста, внимание на то, что из этого сообщения якобы следует, что не найден сам файл сценария . Если не знать подоплеку явления, ситуация кажется подозрительной. Дело в том, что, запуская любую программу, UNIX всегда передает ей один параметр (который имеет индекс 0) - имя этой программы. Но в случае запуска сценария обработчик получит в качестве нулевого параметра не собственное имя, а имя сценария . А когда система этого обработчика не найдет, в сообщении об ошибке он будет упоминаться под новым именем.

Гнезда shell`ов

И еще одно немаловажное замечание. Сначала в UNIX был только один командный интерпретатор , написанный Стивеном Борном (Stephen Bourne), и назывался он просто "оболочка" (т. е. shell , а имя утилиты, для краткости, sh). Это была очень простая маленькая программа , она отлично работала именно как системный интегратор , но во всех остальных ипостасях была довольно слабой. И вот создателям 3BSD пришло в голову, что нужен совершенно новый командный интерпретатор , более удобный при работе в командной строке, с новыми возможностями программирования и с новым синтаксисом, приближенным к языку Си , который и так знаком любому UNIX -программисту. Получившуюся оболочку назвали C shell (за синтаксис команд; имя утилиты - csh ), она была намного мощнее старой, там была работа с историей, достраивание имен файлов, управление заданиями ; появились массивы и много чего еще.

Язык программирования shell имеет несколько конструкций, которые придадут гибкость вашим программам:

  • комметнарии позволят описывать функции программы;
  • "here document" позволяет вам включать в shell программы строки, которые будут перенаправляться как ввод в некоторые команды shell программы;
  • команда exit позволяет завершать программу в нужной точке и использовать коды возврата;
  • конструкции цикла for, while позволяют повторять группу команд в цикле;
  • условные команды if и case выполняют группу команд, если выполнилось некоторое условие;
  • команда break позволяет выполнить безусловный выход из цикла.

9.3.1. Комментарии

Чтобы в программе разместить комментарии, воспользуйтесь знаком #. Если знак # стоит после команды, то сама команда выполняется, а комментарий игнорируется. Формат строки комментария:

#comment

9.3.2. "Here document"

"Here document" позволяет размещать в shell программе строки, которые перенаправляются в качестве ввода команды в этой программе. Это один из способов обеспечения ввода для команды в shell программе без использования отдельного файла. Запись состоит из символа перенаправления << и разделителя, который указывает начало и конец строк ввода. В качестве разделителя может использоваться один символ или строка символов. Чаще всего это знак!.

Формат команды следующий:

Command< ...input lines... delimiter

9.3.3. Использование ed в shell программе

"Here document" предлагает способ использования ed в shell программе. Предположим вы хотите создать shell программу, которая будет вызывать редактор ed, проводить глобальные изменения в файле, записывать изменения в файл и затем завершать работу с ed. На следующем экране приведено содержание программы ch.text, которая выполняет эти задачи:

$ cat ch.text echo Type in the filename read file1 echo Type in the exact text to be changed. read old_text echo Type in the exact new text to replace the above. read new_text ed - $file1 <

Обратите внимание на знак - (минус) в команде ed. Эта опция предотвращает распечатку счетчика символов на экране. Обратите также внимание на формат команды ed для глобальной замены:

G/$old_text/s//$new_text/g

Программа использует 3 переменные: file1, old_text, new_text. При запуске эта программа использует команду read для получения значений этих переменных. Эти переменные содержат следующую информацию:
file - имя файла, который будет редактироваться;
old_text - текст, который будет изменен;
new_text - новый текст.

Переменные вводятся в программу, here document перенаправляет команду глобальной замены, команду записи и команду завершения команде ed. Запустите программу ch.text. Получите следующий экран:

$ ch.text Type in the filename memo Type in the exact text to be changed. Dear John: Type in the exact new text to replace the above. To what it may concern: $ cat memo To what it may concern: $

9.3.4. Коды завершения

Большинство команд shell возвращает коды, которые указывают, успешно ли завершилась команда. Если возвращаемое значение 0(ноль), то команда выполнилась успешно. Коды возврата не печатаются автоматически, но их можно получить как значение специального параметра shell $?.

9.3.4.1. Проверка кодов завершения

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

Рассмотрим следующий пример:

$ cat hi This is file hi. $ echo $? 0 $ cat hello cat: cannot open hello $ echo $? 2 $

В первом случае файл hi существует в вашем справочнике и вы имеете разрешение на чтение. С помощью команды cat вы можете распечатать содержимое файла. Результат команды cat: код возврата 0, который вы получите, задав параметр $?. Во втором случае файл либо не существует, либо вы не имеете право на чтение. Команда cat печатает диагностическое сообщение и возвращает код 2.

shell программа нормально завершается, когда выполнится последняя команда в файле. Однако вы можете использовать команду exit для завершения программы. Более важно то, что вы можете использовать команду exit для получения кодов возврата shell программы.

9.3.5. Циклы

Операторы цикла for и while позволяют выполнить команду или последовательность команд несколько раз.

9.3.5.1. Оператор for

Оператор for выполняет последовательность команд для каждого элемента списка. Он имеет формат:

For variable in a_list_of_values do command_1 command_2 . . . last command done

Для каждой итерации цикла следующий элемент списка присваивается переменной, данной в операторе for. Ссылка на эту переменную может быть сделана в любом месте в командах внутри оператора do. При конструировании каждой секции команд вам необходимо убедиться, что каждому do соответствует done в конце цикла.

Переменная может иметь любое имя. Например, если ваша переменная названа var, то ссылка в списке команд на $var сделает значение доступным. Если оператор in опущен, то значением для var будет набор аргументов, заданный в команде и доступный в специальном параметре $*. Список команд между ключевым словом do и done будет выполнен для каждого значения.

Когда команды будут выполнены для последнего элемента списка, программа будет выполнять строку ниже done.

9.3.5.2. Оператор while

Оператор цикла while использует 2 группы команд. Он будет выполнять последовательность команд во второй группе (список do ... done) до тех пор пока последняя команда в первой группе (список while) возвращает состояние "истина", означающее, что выражение после do может быть выполнено.

Общий формат оператора цикла while:

While command_1 . . . last command do command_1 . . . last command done

Например, программа enter.name использует цикл while для ввода списка имен в файл. Программа состоит из следующих командных строк:

$ cat enter.name while read x do echo $x>>xfile done $

Внеся некоторые добавления, получим следующую программу:

$ cat enter.name echo Please type in each person"s name and than a echo Please end the list of names with a <^d> while read x do echo $x>>xfile done echo xfile contains the following names: cat xfile $

Обратите внимание, что после завершения цикла программа выполняет команды ниже done.

В первых двух командах echo используются специальные символы, так что вы должны воспользоваться кавычками для отмены специального значения. На следующем экране приведены результаты выполнения программы enter.name:

$ enter.name Please type in each person"s name and than a Please end the list of names with a <^d> Mary Lou Janice <^d> xfile contains the following names: Mary Lou Janice $

После того, как цикл завершится, программа распечатает все имена, содержащиеся в xfile.

9.3.6. Использование /dev/null

Файловая система имеет файл /dev/null, где вы можете хранить нежелательный вывод. Например, если просто ввести команду who, то система ответит, кто работает в системе. Если вы перенаправите вывод этой команды в /dev/null:

Who > /dev/null

то не получите ответа.

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

Оператор if ... then

Команда if говорит shell программе, что нужно выполнить последовательность команд после then, если последняя команда в списке команд конструкции if выполнилась успешно. Конструкции if заканчиваются ключевым словом fi.

Общий формат конструкции if:

If command_1 . . . last command then command_1 . . . last command fi

Например, shell программа search демонстрирует применение конструкции if ... then. Программа search использует команду grep для поиска слова в файле. Если grep выполнилась успешно, то программа отображает найденное слово. Экран будет выглядеть следующим образом:

$ cat search echo Type in the word and the file name. read word file if grep $word $file then echo $word is in $file fi $

Эта программа отображает вывод команды grep. Если вы хотите сохранить ответ системы на команду grep в вашей программе, то воспользуйтесь файлом /dev/null, изменив командную строку if на следующую:

If grep $word $file > /dev/null

Теперь выполните команду search. Она ответит только сообщением, указанным после команды echo.

Конструкция if ... then ... else может исполнять альтернативный набор команд, стоящий после else, в случае, если последовательность if является ложью. Формат этой конструкции следующий:

If command_1 . . . last command .linthen command_1 . . . last command else command_1 . . . last command fi

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

$ cat search echo Type in the word and the file name. read word file if grep $word $file > /dev/null then echo $word is in $file else echo $word is NOT in $file fi $

Команда test

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

Test -r file истина, если файл существует и доступен для чтения; test -w file истина, если файл существует и доступен для записи; test -x file истина, если файл существует и является выполняемым; test -s file истина, если файл существует и имеет как минимум один символ; test var1 -eq var2 истина, если var1 равно var2; test var1 -ne var2 истина, если var1 не равно var2.

Пример. Создадим shell программу, которая перемещает все исполняемые файлы из текущего справочника в ваш справочник bin. Для этого воспользуемся командой test -x для выбора исполняемых файлов. Программа mv.file будет выглядеть следующим образом:

$ cat mv.file echo type in the directory path read path for file do if test -x $file then mv $file $path/$file fi done $

Конструкция case ... esac позволяет выбрать вам один из несколько шаблонов и затем выполнить список команд для этого шаблона. Выражение-шаблон должно начинаться с ключевого слова in, а правая круглая скобка должна быть помещена после последнего символа каждого шаблона. Последовательность команд для каждого шаблона заканчивается двумя знаками;;. Конструкция case должна быть закончена ключевым словом esac.

Общий формат конструкции case:

Case word in pattern1) command line 1 . . . last command line ;; pattern2) command line 1 . . last command line ;; pattern3) command line 1 . . last command line ;; *) command line 1 . . last command line ;; esac

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

Если первый шаблон не найден, то осуществляется переход ко второму шаблону. Если любой шаблон найден, то программа не рассматривает остальные шаблоны, а переходит к команде, следующей за esac. Знак * используется как шаблон для поиска любого word и таким образом дает вам набор команд, который будет выполнен, если никакой другой шаблон не будет найден. Поэтому шаблон звездочка (*) размещается как последний шаблон в конструкции case, чтобы другие шаблоны были проверены первыми. Это поможет вам обнаружить некорректный и неожиданный ввод.

В шаблонах могут использоваться метасимволы *, ?, . Это обеспечивает гибкость программ.

Рассмотрим пример. Программа set.term устанавливает переменную TERM в соответствии с типом терминала, который вы используете. Применяется следующая командная строка:

TERM=terminal_name

Шаблон * стоит последним в списке шаблонов. Он выдает предупреждающее сообщение, что для указанного типа терминала нет соответствующего шаблона и позволяет вам завершить конструкцию case.

$ cat set.term echo If you have a TTY 4420 type in 4420 echo If you have a TTY 5410 type in 5410 echo If you have a TTY 5420 type in 5420 read term case term in 4420) TERM-T4 ;; 5410) TERM-T5 ;; 5420) TERM-T7 ;; *) echo not a correcr terminal type ;; esac export TERM echo end of programm $

9.3.8. Безусловная передача управления

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

В предыдущем примере программы set.term вы можете использовать команду break, вместо echo, чтобы выйти из программы, как приведено в следующем примере:

$ cat set.term echo If you have a TTY 4420 type in 4420 echo If you have a TTY 5410 type in 5410 echo If you have a TTY 5420 type in 5420 read term case term in 4420) TERM-T4 ;; 5410) TERM-T5 ;; 5420) TERM-T7 ;; *) break ;; esac export TERM echo end of programm $

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