Интерфейс командной строки

Кувшинов Д.Р.

2015


Общее оглавление


Введение

Операционная среда или окружение environment — интерфейс, предоставляемый пользователю или программе операционной системой. В частности, пользовательский интерфейс является частью операционной среды.

Командная строка command line — принцип организации пользовательского интерфейса на основе ввода текстовых команд с клавиатуры и текстового вывода результатов на экран. Интерфейс на основе командной строки — command line interface, CLI.

Оболочка командной строки или просто оболочка shell — программное обеспечение, отвечающее за поддержку командной строки (обычно это компонент ОС, но может быть и сторонним ПО). Примеры: cmd.exe и Powershell в Windows, sh, csh, bash, ksh и др. в Unix-подобных системах. Оболочка командной строки предоставляет собственное окружение: “переменные среды” environment variables (глобальные и локальные для текущего сеанса) и интерпретатор текстовых команд.

Пакетный файл batch file или сценарий — содержащий команды оболочки файл, который можно запустить на исполнение как исполняемый файл.

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

Консоль console — исторически реализация терминала с клавиатурой и текстовым дисплеем. В настоящее время это слово часто используется как синоним сеанса работы или окна оболочки командной строки. В том же смысле иногда применяется и слово “терминал”.

Консольное приложение console application — вид ПО, разработанный с расчётом на работу внутри оболочки командной строки, т.е. опирающийся на текстовый ввод-вывод.

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

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

Впоследствии миниатюризация вычислительных устройств позволила сделать схему “ЭВМ ↔ сеть ↔ терминалы” необязательной, совместив ЭВМ и терминал в одном устройстве — персональном компьютере. Тем не менее, старый текстовый интерфейс продолжил существование ввиду своей исключительной простоты. Все современные операционные системы, несмотря на наличие во многих случаях развитого графического интерфейса пользователя и новых устройств ввода (мыши, тачскрина и т.д.), могут работать и в режиме текстового ввода-вывода (“консоли”).

Обычно операционные системы предоставляют специальную программу — оболочку командной строки, работающую в текстовом режиме и принимающую некоторый относительно стандартизованный набор команд, с помощью которых пользователь может управлять работой ОС, запускать другие программы. Эту программу “по старой памяти” и называют “терминалом” или “консолью”.

В рамках стандартов языков C и C++ определён базовый набор средств, позволяющий работать в режиме текстового интерфейса. Соответственно, например, проект приложения Visual C++, использующий эти средства, называется “консольным”.

Общая схема работы консольного приложения показана на рисунке.

Схема работы консольного приложения
Схема работы консольного приложения

Разложим содержание этой схемы по пунктам.

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

/*
Система передаёт параметры командной строки
в виде массива C-строк argv, размер которого
передаётся параметром функции argc.
*/
int main(int argc, char* argv[])
{
  // Выведем содержимое каждого параметра.
  for (int i = 0; i < argc; ++i)
    cout << i << ": \"" << argv[i] << "\"\n";

  // Программа завершилась успешно,
  // вернём системе код успеха.
  return EXIT_SUCCESS;
}

При вводе в стандартный поток ввода с консоли можно явно завершить ввод с помощью управляющего символа “конец файла” end-of-file, EOF. В Windows для этого нужно нажать Ctrl+Z и Enter, в Unix-подобных системах с той же целью традиционно используется сочетание Ctrl+D.

Работа с командной строкой

Вариант для Visual C++. Создайте проект консольного приложения с названием “HelloWorld” и введите приведённую выше программу. Откройте свойства проекта. В разделе “Отладка” введите следующее значение в параметр “Аргументы команды”.

\a -b c >log.txt

Параметры командной строки, используемые при запуске программы из IDE
Параметры командной строки, используемые при запуске программы из IDE

Запустите отладку. Теперь в папке проекта возник файл log.txt, содержащий четыре строчки текста. Нулевым параметром командной строки передаётся сама команда со всеми параметрами.

“Аргументы команды” позволяют задать параметры командной строки, с которыми будет запущено наше приложение при отладке. В качестве разделителя используется пробел, поэтому если требуется передать параметр, включающий пробелы, то следует заключить его в двойные кавычки, например "Program Files". Кроме собственно параметров, которые получит приложение через argc и argv, можно указать директивы командной строки.

Например, можно явно указать источник потока stdin, записав <источник. Например, вместо того, чтобы вводить данные с клавиатуры, в качестве источника можно подключить файл. Аналогично, вместо того, чтобы выводить данные, отправляемые в stdout, в окно консоли, можно сохранить их в файл, записав >файл. По умолчанию, файл, в который перенаправляется поток, перезаписывается. Директива >>файл добавляет новое содержимое в конец файла.

Даже если мы перенаправили stdout в файл, сообщения об ошибках, отправляемые в stderr, всё равно будут появляться в окне консоли. Чтобы сохранять их в отдельный файл, можно дописать 2>файл. Дескриптор 2 привязан к stderr (соответственно, 1 – к stdout, 0 – к stdin). Директива 2>&1 свяжет stderr с stdout так, что символы, приходящие в stderr будут отправлены туда же, куда подключен stdout.

Одним из стандартных компонентов ОС Windows является интерпретатор командной строки cmd.exe. Интерпретатор командной строки вызывается автоматически при запуске пакетных файлов (в Windows они имеют расширение .cmd и .bat, в Unix-подобных системах популярны расширения .run и .sh), содержащих команды.

В качестве примера создадим файл test.cmd в одной папке с .exe нашего консольного приложения. Откроем его в текстовом редакторе и введём две строчки

HelloWorld beth daleth aleph gimel | sort
pause

Интерпретатор командной строки имеет набор встроенных команд. Помимо них, любой исполняемый или пакетный файл может выполнять роль команды. Команды можно объединять с помощью ряда директив. Например, использованная выше | (её часто называют “пайп” от англ. pipe — “труба”, “трубопровод”) связывает поток вывода команды слева с потоком ввода команды справа. Благодаря этому мы видим строки, выведенные приложением, отсортированными.

Директивы команда1 && команда2 и команда3 || команда4 позволяют реализовать условное исполнение: так команда2 будет выполнена только в том случае, если команда1 вернула успех, а команда4 будет выполнена только в том случае, если команда3 вернула неуспех. Данное поведение напоминает поведение логических операторов “и” и “или”, вычисляемых по “короткой схеме” (те же обозначения в C: && и ||, соотвественно).

Если подключить стандартный заголовочный файл cstdlib, то становятся доступными функции void exit(int), int system(const char*) и char* getenv(const char*), помогающие при работе в режиме командной строки.

Функция exit позволяет завершить работу программы из любой её точки и принимает код ошибки, который будет возвращён ОС.

Функция system позволяет выполнить команду (переданную в виде C-строки) в режиме командной строки. Например, в ОС Windows

system("cls");

очистит экран консоли от текста (аналогом cls в Unix-подобных системах является команда clear).

Набор команд и смысл возвращаемого функцией system числа зависит от ОС и реализации стандартной библиотеки.

Стандарт гарантирует возможность проверить доступность интерпретатора командной строки путём передачи нулевого указателя:

if (!system(nullptr))
  cerr << "command line interpreter is not available\n";

Функция getenv позволяет получить значение переменной среды с известным именем. Например, переменная среды PATH содержит список директорий, в которых производится поиск исполняемых или пакетных файлов при вводе команды, не поддерживаемой интерпретатором непосредственно. Следующий код выведет значение этой переменной на экран.

const char *path = getenv("PATH");
cout << "PATH = " << path << endl;

Общее оглавление

Кувшинов Д.Р. © 2015