Командная строка: команды, параметры, перенаправление ввода
Структура команды
Кроме ряда символа, которые являются специальными про вводе, некоторые являются специальными при выводе: переставляет курсор, прекрашивает буквы, и так далее. Такие управляющие последовательности (будем отличать их от упр. символов) вводятся для того, чтобы не отменять того, что терминал тупой. Терминал --- такая штука навроде телетайпной ленты. То, что некоторые последовательности к чему-то приводят, терминалу неинтересы, они интересны атворам программ. Таки образом, мы сравнительно за недорого можем первратить терминал из интерфейса коммандной строки в интерфейс как формочки. Многие знают про mc. mc не пользуется никакими графическими примочками, и тот псевдографич. вывод определённых байтиков в опр. места. И лектор говорил, что есть дона беда с упр. посл. --- у разных терминалов они разные. Дело в том, что раньше терминалы были не программами а железаками, делали их те, кто по совместительству делал ..., и понапридумывали их все. И для того, чтобы свести это к единому знаменателю, придумали это понаписать в одну БД. Для справки, в линуксе все те эмуляторы терминала, будут примерно одного типа --- vt100. vt100 --- базовый тип, над ним нарастают разные vt200, xterm, linux. И хоть железяки такие не выпускают, эмуляторы могут отличаться.
Идея интерфеса командной строки состоит в том, что вводим некоторые высказывания, состоящие из слов, команда состоит из операции и необязательных параметров.
<операция> [<параметры>]
Это то, что вы вводите в командной строке. Если вы говрите ls -s a*, то ls --- операция, -s, a* --- параметры, причём a* раскрывается в несколько параметров.
Операции могут быть двух видов: команда самого шелла, для команды никакой новый процесс запускать не надо. Второй вид --- программа. Что касается параметров, они отже двух видов: объекты и ключи. В приведённом примере параметр-объект --- file, параметр-ключ --- -s. Между ними будут разделители. Командная строка читается как предложения, предложения состоят из слов, слово --- посл. символов, не явл. разделителем. У этой команды два параметр. В чём разница? Что касается параметров-объектов, то это такие ..., это просто некие объекты для нашей программы. Для ls --- имена файлов, для которых надо выводит информацию Для echo --- объекты --- строки, которые надо вывести. Параметр-объект именует объект, с которым будет работать программа. Ключ имеет несколько наукообразное название --- модификатор выполнения. ls выводит информацию о файлах, и если ключей нет, то выводит только имена. Ключ -s указывает, что нужно выводить некоторую дополнительную информацию --- размер файла в блоках.
Традиционно договорились, что ключи в unix начинаются на минус. Ключи бывают двух видов, во-первых, однобуквенные. Чем хороши однобуквенные ключи? Если использовать принцип аббревиативности (ключ начинается на ту же букву, что и слово, которое он символизирует), то их достаточно просто запомнить и достаточно легко вписать в командную строку. Клчюей у ls много. Кроме того, можно склеить несколько ключей, указав их с одним минусом: -saF. Но принцип аббревиативности тяжело соблюдать, т.к. букв много и они часто бывают заняты, в итоге ключи уже плохо запоминаются. Поэтому ещё есть полнословные ключи, т.н. gnu-style. Такой ключ предваряется двумя минусами, дальше идет целое слово или даже несколько слов. Писать всё это безобразие руки отвалятся, но понятно, что если написано –-long, то понятно, о чёми речь, а если -l, то не сразу. В силу того, что есть удобные библиотеки для разбора командной строки, большинство программ имеет и такие, и сякие ключи. Обычно, весь набор ключей представлен в полнословном варианте и некоторое подмножество --- однобуквенными эквивалентами. . Итак, когда мы выводим команду, она является некоей операцией, остальное будут параметрами, ключи бывают тоже двух видов. Лектор надеется в ближайшее время делать страничку, посвящённую лекциям, и там он сошлётся на учебник, где есть больше. Этот вопрос пока закрыли.
Лектор хочет рассмотреть. тему, связанную с перенаправлением ввода-вывода. Просто здесь, по нормальному плану, надо бросить всё и рассказать про то, как ман читать. Но сегодня всё-таки про терминалы.
Дело в том, что некоторые символы в командной строке интерпретируются самим шеллом и не являются командой в командной строке. На самом деле шелл разделяет символы на три класса: разделители, неспециальные символы, специальные символы. Один символ лектор уже упомянул, это символ *.
Перенаправление ввода/вывода
Чтобы немного докончить тему с процессами и терминалами, рассмотрим несколько символов, которые управляют перенаправлением ввода-вывода.
Когда ОС запускает опр. программу, у этой программы сразу доступно три потока данных, одно на ввод и два на вывод. Есть стандартный ввод, stdin, поток данных номер 0; стандартный вывод? stdout --- поток данных 1; stderr --- 2. С ними можно работать как с файлами. Поскольку манипуляция с потоками данных есть наиболее ффективный способ организации работы программ, то шелл должен это уметь. Любая программа имеет три потока данных. Для тех, кто это проходил, не секрет, что три этих дескриптора прото налседуются, поскольку там случилса fork, потом exec. Но, слава богк, когда программа выполняется в активном режиме, всё происходит не так: делается форк, получается два шелла, отличающиеся только результатом форка. Потомок запускает программу, в это время поток-папа выполняет wait(), и ждёт завершения. Это не вполне похоже на то, как мы могли бы себе представить. Можно было бы подумать, что есть специальный вызов «запустить программу», но это было бы неудобно.
Далее, можно перенаправить вывод. Программа как будет раньше выводить в стандартный вывод, так и будет, и ей будет хорошо. А перенаправление сделает потомок. Как это сделать: ls > file. Это больше приводит к следующему: перед экзеком потомок закрывает-открывает файл. Можо написать перенаправление из файла в файл. Если >>, то это операця дописи в файл. Становится вопрос: зачем тогда вообще придумали stderr, если это тоже вывод, а второе --- как его перенаправить? Есть ещё такая операция --- pipeline (|), в прошлый раз приводился пример cal | wc. При этом создаётся pipe, никакого файла не создаётся, только два файловых дескриптора. И всё, что пишет cal, читает wc. можно создавать трубопровод: ls |sort -r | tail 10. Как перенаправить stderr? Использовать 2>.
cmd |& cmd --- перенаправить оба потока вывода на ввод первой команде.
Чтобы окончательно сбить с толку, лектор намекнёт на то, что там ещё десятки перенаправлений вывода. Например, есть такая штука: cmd > file1 > file2.
Задача: сформулировать выдачу из нескольких строк и посчитать количество слов. Первый выход:
echo "ewfsfs snegdfsdfsdfs --- шелл будет считать, что это одни параметр dfsfs" | wc -c --- выведется некоторое количество символов
Есть другой вариант, воспользоваться
wc -c ewfsfs snegdfsdfsdfs dfsfs
Есть вариант
cmd <<< string
Мы добрались до второй части разговора, как манипулировать процессами. Это такая хитрая штука. В каждыцй момент времени могут выполняться сразу несколько задач, процессов. Каждый процесс имеет уникальный идентификатор, именуемый PID. Список всех процессов можно посмотреть командой ps -ef, или ps ax. Поскольку есть единственный способ породить процесс --- форк, то понятно, кто какой процесс породил. Кромеп того, каждый процесс имеет идентификатор папочки, ppid. Если папа умер, то PPID становится равен 1, это PID процесса init. Всё это происходит на уровне ядра, и как-то на это воздействовать невозможно. Возвращаясь к перенаправлению ввода-вывода, можно сказать, что с терминалом в один момент может быть связан только один процесс. Вопрос, где взять столько терминалов? Помимо активных процессов есть фоновые процессы, которые могут быть связаны толко по выводу. Таких процессов может быть много. Можно вообще отвязать процесс, для этого есть nohup. Если написать команду и поставить ампервенд, то процесс будет запущен в фоне. Что можно с ним сделать? Можно ему послать сигнал. Всякие добрые шеллы пишут PID запущенного процесса, специально для таких целей. Есть команда kill, у которой есть необязательный параметр --- сигнал.
Когда лектор говорил, что процесс, запущенный в фоне, остаётся привязанным к терминалу, лектор говорил, что фоновый процесс можно сделать активный, а активный --- фоновым. Как это делается: этому процессу... Все процессы, запущенные из под данного шелла с помощью команды jobs можно посмотреть. Они нумеруются подряд. Активному процессу можно послать сигнал suspend (Z), после этого активным делается его папочка, шелл. После этого можно выдать команду bg (background), тогда шелл отвяжет его и переведёт в бэкграунд. Точно также можно сказать fg, и процесс, первый попавшийся или специфицированный, перейдёт в активную форму. Зачем всё это делать. Ответ такой: управляющий символ. Если процесс привязан к терминалу, если процесс активен, то нажатие некоторых упраалвяющих клавиш приводит к передаче ему сигнала. Вместо kill можно перевести его в фореграунд и сказать C. Терминалом управляет stty, у неё есть команды для посылки сигналов. Если испортить терминал, то можно потом скачать stty sane ^J
Третье, работа с командной строкой. Тут есть два с половиной эшелона: первое --- stty, там есть erase. Тут можно сказать stty erase ^H. Второй эшелон состоит в следующем: точно такая же фигня, абсолютно отвязанная от терминала, заложана в БД терминал капабилитиес. Эта фигня должна соответствовать типу терминала, тому, что лежит в $TERM. Третий эшелон: многие программы, например, баш или вим, то там это пальцами прибито.
Вообще, лектор просит обратить внимание на команду stty.