Введение в Linux: рабочий стол, ИКС, основы использования шелла, терминал
Примечание. Эта лекция очень сильно пересекается со следующими:
Главы книг:
Модули
Готов? |
Название модуля |
Чтение (ак. ч.) |
Подготовка (астр. ч.) |
Написание (дни) |
уровень |
Maintainer |
Started |
Should be done |
End date |
90% |
1 |
1 |
1 |
1 |
PavelSutyrin, GeorgeTarasov + VsevolodKrishchenko, VsevolodKrishchenko |
||||
90% |
1 |
1 |
1 |
1 |
SergeyKorobkov + ОльгаТочилкина, ОльгаТочилкина, VsevolodKrishchenko |
||||
90% |
1 |
1 |
1 |
1 |
|||||
90% |
1 |
1 |
1 |
1 |
|||||
20% |
1 |
1 |
1 |
1 |
|||||
|
5 |
5 |
5 |
5 |
|
|
|
|
|
|
Готово: 0 (0%) |
0 |
|
0 |
|
|
|
|
|
|
Не готово: 5 (100%) |
5 |
|
5 |
|
|
|
|
|
Необходимые знания
Материалы
Полиси
На данный момент для координирования работ используется макрос ExtractModules (тот же, что и в PspoModules). Возможно, впоследствии будет написано нечто более специфичное для данных работ.
- Над каждым модулем работает один расшифровщик (указывается первым в списке сопровождающих модуль),один переводчик (указывается вторым в списке) и минимум один технический редактор (тот, кто вычитывает, указывается третьим в списке).
- Разбивка прогресса по процентам:
0%
Сырой конспект
20%
Дешифрованный конспект
50%
Конспект, переведённый на русский язык
70%
Вычитанный конспект
90%
Иллюстрирование, расстановка ссылок, перенос в модули
100%
Результат работ над частью лекций проверен FrBrGeorge
- Как только Вы считаете, что закончили свою часть работы, просьба установить соответствующее количество процентов
- Промежуточное количество процентов в промежуточных сохранениях приветствуется
Пожелания к ролям
Расшифровка — по возможности полное восстановление структуры и смысла лекции по конспектам и (если есть необходимость) по аудиозаписям. в эту задачу входит расстановка имеющихся иллюстраций (typescript, konsole.log, снимки экрана)
Перевод на русский — выравнивание стилистки и корректировка владения русским языком. Просьба не очень самовыражаться (чтобы не создавать стилистического разнобоя)
Вычитка — проверка получившегося текста на (1) соответствие действительности (2) доходчивость (в том числе на предмет нехватки иллюстраций)
Лекции
Что такое операционная система
Управление ресурсами компьютера
Одно из определений операционной системы (ОС) гласит: операционная система --- это средство управления ресурсами компьютера. Можно выделить три уровня разделения ресурсов, на каждом из которых распределение и использование ресурсов компьютера происходит по-своему.
Однозадачный режим
Начальный уровень, на котором не нужны никакие дополнительные действия для обеспечения доступности ресурсов компьютера --- когда у нас есть ровно одна программа, которая полностью распоряжается всеми ресурсами компьютера, пока она не закончит свою работу. Такая система называется однозадачной, и то, насколько разумно она распоряжается аппаратными ресурсами, может повлиять только на работу единственной запущенной программы. Если программа написана плохо, например, пожирает память, то в конце концов она просто перестаёт работать, потому что оперативной памяти ей не хватит. Хорошо написанная программа должна успешно распоряжаться процессором, всей оперативной памятью и всеми внешними (по отношению к процессору) устройствами.
Много ли нужно программного обеспечения, чтобы позволить этой задаче эффективно использовать память и устройства и нужно ли создавать какое-то отдельное программное обеспечение для поддержки этого процесса? Возможный ответ --- "нет", так как запущенная программа, как правило, содержит в себе все необходимое ПО. Типичный пример -- это старинная игровая консоль (SEGA, SNES), использующая картриджи. Каждый картридж --- отдельная программа, загружающаяся и работающая по принципу однозадачной системы.
Унификация доступа
Однако даже при однозадачной системе обычно неразумно всю задачу организации доступа к ресурсам возлагать на прикладную программу, поскольку это сильно затрудняет их разработку.
Как минимум, хотелось бы унифицировать способ использования различных аппаратных ресурсов, например внешних устройств. Для решения этой задачи необходима некая прослойка между программой, которая пользуется ресурсами компьютера, и самими ресурсами. Эта прослойка будет скрывать от программы подробности того, как именно этими ресурсами воспользоваться. Рассмотрим это на примере графической платы: мы поменяли видеокарту, вместе с ней поменяли прослойку, которая обеспечивает доступ по стандартному (и не зависящему от конкретной карты) протоколу к ресурсам этой видеокарты, и прикладные программы не "заметили" изменений, хотя в действительности по шине PCI передаются уже принципиально другие данные.
Таким образом, даже на уровне однозадачной системы встает вопрос унификации доступа к ресурсам. Идея в том, чтобы ПО не принимало во внимание особенности аппаратного обеспечения, чтобы за это отвечала указанная прослойка. Зависящая от конкретной аппаратуры часть этой прослойки называется драйвером.
Многозадачный режим. Разделение доступа
Как только выясняется, что ресурсами компьютера пользуются несколько различных программ (назовём этот режим многозадачным), сразу возникает вопрос -- к каким ресурсам какие программы имеют доступ? Простейший вариант: пусть программы выполняются по одной друг за другом -- сначала отработает первая, затем вторая и т.д. Даже в этом случае, если они работают друг за другом и не знают о существовании друг друга, возникает вопрос организации дисциплины доступа к таким внешним ресурсам, которые существуют в течение их работы, например, к накопителю данных.
Разумеется, если программы работают по очереди, нет необходимости защищать, скажем, оперативную память, но общее для всех хранилище данных на диске хорошо бы организовать таким образом, чтобы одна программа знала о том, где хранит свои данные другая программа, для того, чтобы избегать коллизий. Если это файловая система, как в Linux, неплохо, если бы программа работала с именами файлов, и любая операция с некоторым файлом должна быть заложена в программу сознательно.
Еще более очевидна необходимость разделения ресурсов, когда мы имеем многозадачную систему с параллелизмом или псевдопараллелизмом (что вообще-то почти одно и то же с точки зрения разделения ресурсов). Параллелизм возможен при наличии нескольких процессоров, одновременно выполняющих разные программы; псевдопараллелизм -- это ситуация, когда эти программы в действительности работают последовательно, но для пользователя создается впечатление, что они работают параллельно, и происходит это так: один квант времени работает одна программа, потом она приостанавливается, следующий квант времени работает другая программа, следующая, потом снова начинает работать уже первая программа, и все снова. Выполняющуюся (загруженную в память) программу называют процессом.
Псевдопараллелизм --- наиболее распространенный вариант, его еще называют вытесняющей многозадачностью. Программы не обязательно выполняются в строгой последовательности, возможно (как в случае, когда приложение ожидает завершения операции ввода-вывода) изменение порядка их работы. В целом задача планирования процессов достаточно сложна, например 2007-й год прошёл под флагом революции в области планировщиков процессов в UNIX-системах (как в Linux, так в BSD-подобных), этой теме был посвящен отдельный семинар.
Таким образом, в многозадачных системах все ресурсы компьютера --- процессорное время, оперативная память, внешние устройства -- должны быть разделены между всеми работающими программами. Например, в случае псевдопараллелизма нужно создать дисциплину распределения доступа к процессору (например, мы можем захотеть, чтобы "дележ" процессорного времени был "справедливым" --- каждой программе поровну). Другим примером будет разделение оперативной памяти: нужно определить дисциплину распределения памяти, а так же организовать доступ к ОП таким образом, чтобы одна программа не могла случайно испортить содержимое участка памяти другой программы, поскольку эти программы не обязаны знать о том, что они сосуществуют вместе на одном компьютере. Третьим примером будет разделение принтера или сканера --- пока принтер полностью не завершил обработку одной заявки на печать, он не может начать обработку следующей.
Таким образом, все ресурсы, которые используют прикладные программы, должны быть явно обозначены, и должны существовать договоренности об их использовании, чтобы ситуация, когда одна программа модифицирует какой-то ресурс, принадлежащий другой программе, была исключительно штатной и контролируемой. Совокупность этих правил называют механизмом разделения ресурсов.
Разделение доступа к ресурсам
Как следует из проблем создания систем с параллельным выполнением программ, задача управления ресурсами оказывается связанной с задачей разделения доступа к ресурсам. Поэтому второе определения операционной системы гласит: операционная система --- это средство разделения ресурсов компьютера между прикладными программами.
Разделение центрального процессора
В персональных машинах чаще всего используется всего лишь один центральный процессор. Ресурсы ЦП включают в себя не только время его работы, но и объекты, связанные с хранением данных (регистры процессора). Это значит, что когда мы организуем псевдопараллелизм, мы должны предусмотреть не только ситуацию разбиения по времени (некоторое время работает одна, а некоторое --- другая задача), но и механизм сохранения тех элементов памяти, которые не дублируются для каждой программы, от одной программы, на то время, пока работает другая программа. К таким элементам относятся прежде всего регистры центрального процессора.
Всё состояние системы (в первую очередь --- центрального процессора), которое необходимо сохранить, чтобы в будущем продолжить выполнение процесса, называется контекстом процесса.
Это что значит, что в случае псевдо-параллелизма мы имеем один процессор, набор оперативной памяти, а в очереди сидят процесса (процесс-1, процесс-2 и так далее). С каждым созданным процессом связан контекст процесса, сохранённый в той же оперативной памяти. Когда процесс дожидается своей длои процессорного времени, то перед его выполнением, контекст подгружается, в частности, восстанавливаются значения регистров процессора. Затем процесс некоторое время (обычно порядка милисекунд) выполняется, после чего останавливается и контекст на момент прекращения выполнения сохраняется обратно. Затем подгружается контекст следующего по очереди процесса, он выполняется, и так далее. Даже такая с виду простая штука, как разделение ресурса под названием "центральный процессор" уже приводит к довольно сложным механизмам разделения доступа к этому ресурсу: квантование выполнения и сохранение контекста.
Разделение оперативной памяти
Тут ситуация чуть более простая, если в ней не разбираться, и чуть более сложная, если в ней разбираться досконально. #Никому не надо рассказывать слишком подробно, что На некотором уровне абстракции оперативная память представляет собой последовательность ячеек с номерами от 0 до самого большого значения, и сколько у нас воткнуто в плату памяти, столько и будет. Однако, в действительности всё значительно сложнее.
Существует несколько видов адресов памяти. В системах, которые ведут свое происхождение от однозадачных систем и не обеспечивают надлежащее разделение памяти между задачами (типичная такая система -- DOS, а также, с оговорками, Windows 3.*), основной являются физические адреса памяти --- одна программа занимает адреса от 1000 до 100000, другая от 120000 до 202000 байт, и так далее.
Если при этом одной программе по причине ошибки приходило в голову исписать нулями не свою, а "чужую" память (начав, к пример, в своей, а в результате ошибки убежав за границу), то тогда она убивала всю оперативную память, доступную операционной системе, и компьютер "зависал". Типичная ситуация в DOS: написал программу на языке Си с ошибкой, запустил, в итоге перегрузил компьютер. В младших версиях Windows наблюдалось то же самое, причём отдельные рецидивы были вплоть до Windows 98 (но не в линейке полноценных ОС Windows NT).
Операционные системы, которые обеспечивают нормальное разделение памяти, пользуются аппаратным страничным механизмом разделения памяти, котому уже около 30-ти лет, а в недорогих компьютерах он появился вместе с процессором Intel i386 почти четверть века назад. Устроен этот механизм следующим образом. Вся оперативная память делится на страницы некоторого фиксированного размера (обычно по 4096 байт). Пусть запускаются два процесса в псевдо-параллельном режиме, причём никто из них не ведёт обмен с внешними устройствами, а жаждет лишь выполняться на процессоре. Для каждого создается контекст процесса, набор регистров, который нужно хранить, и все остальное, потом каждый из них запрашивает себе память, которая ему выделяется. Куски памяти, запрошенные разными процессами, с физической точки зрения перемешаны совершенно произвольно. Но реальных адресов с 0 до полного объема памяти ни один процесс не наблюдает. У него происходит аппаратно поддерживаемое со стороны процессора преобразования виртуального адреса, с которым они работают, в адрес физический.
При этом все страницы памяти, принадлежащие процессу, складываются в некоторую т.н. виртуальную память с непрерывной адресацией (допустим, объёмом 100 Mb), которую, собственно, и "видит" этот процесс. В таких случаях в понятие контекста процесса включается указанное преобразование, поскольку для каждого процесса оно своё. Когда процесс обращается к памяти, он видит только ту память, которую ему выдали, от нулевого адреса и до конца запрошенной памяти (видит он даже до физически максимального адреса). Доступ же в память напрямую, по произвольному физическому адресу, процессу запрещён.
Из скольких страниц состоит выделенная процессу память и какие у них физические адреса --- процессор не волнует, это проблема операционной системы. Пусть у нас всего 1 Гб памяти, процесс заказал 100 Мб, он 100 Мб получил, а эти 100 Мб собраны из 25600-ти страниц памяти по 4 Кб каждая.
Аналогичная ситуация происходит со вторым процессом программой, который так же видит только свою память, строго от нуля, чужую память он не видит в принципе. Таким образом, при использовании виртуальной памяти программа не может случайно испортить чужую память. По предварительной договорённости можно обратиться в вышестоящей организации и сказать: у меня есть две программы, которые используют общий сегмент памяти, разреши им пользоваться, потому что так проще данные передавать: одна запишет, другая возьмёт. Операционная ситсема ответит: хорошо, тогда вот вам еще один сегмент, который будет подключен в адресное пространство обоих процессов (со своими адресами). Когда один процесс в него пишет, другой процесс сразу видит изменения. Но, в отличие от ситуации, когда программа расписала нулями всю чужую память, эта ситуация --- контролируемая. Вы написал программы так, что они заказали себе один и тот же сегмент, и по Вашей воле производят там изменения.
Ещё один достоинством страничной организации памяти и виртальных адресов является возможность записать малоиспользыемые процессом таблицы памяти на диск, а при обращении к ним считать их обратно в память, причём все это совершенно незаметно для процесса. Так устроена подкачка памяти с диска ("своп").
Разделение внешних устройств
Если система многозадачная, то разделения требуют вообще все ресурсы, не только процессор как время и как недублируемая память, и не только оперативная память как объект желаний процессов. Разделения требует, например, звуковая карта, т.к. если несколько программ пытаются играть звук, это, во-первых, отвратительно слышно, во-вторых, если не организован процесс разделения, то первая программа может получить доступ к ресурсу, а все остальные могут его и не получить. Если операционная система предоставляет некоторый интерфейс к звуковой карте, это значит, что либо в каждый момент времени по отношению к звуковой карте она "однозадачная": первая по порядку запуска программа получает полный доступ, а всем остальным не хватило, т.е. имеет место монопольный доступ, либо она как-то решает проблему разделения звуковой карты. Для решения этой проблемы система может поддерживать несколько виртуальных звуковых карт, а каждой процесс будет работать со своей виртуальной картой. Затем система организует наложение друг на друга звуков от нескольких процессов и передачу результатов физической звуковой карте. То же самое касается видеокарты, периферийных устройств и так далее, причём в случае принтера "наложение" недопустимо, а в случае видеокарты происходит сплошь и рядом.
Ограничение доступа
Задачи операционной системы не ограничиваются обеспечением доступа к ресурсом и их разделением между программами. В случае многозадачной системы постоянно возникает ограничить ряд процессов таким образом, чтобы они не смогли получить доступ к каким-либо ресурсам в принципе. Пример: допустим я храню пароли в текстовом файле и не хочу, чтобы их мог подсмотреть процесс, запущенный любым другим пользователем и вообще любой процесс, которому я не доверяю.
В результате решения этой проблемы мы приходим к тому, что система не просто многозадачная, но и задачи бывают разные с точки зрения уровня доступа. Про одни задачи известно, что им можно иметь доступ к некоторому ресурсу, а про другие известно, что нельзя. В простейшем случае задачи делятся на группы, принадлежащие разным пользователям, причём это могут быть как фиктивные системные пользователи, так и пользователи, связанные с пользователями-людьми. Одной группе задач пользователь разрешает иметь доступ к некоторому ресурсу, а другим группам --- не разрешает. И мы переходим от системы многозадачной к системе многозадачной и многопользовательской.
Если в случае многозадачной системы все задачи была с равными правами и главной целью системы было обеспечить невозможность случайного доступа к чужим ресурсам, то в случае многопользовательской системы разные задачи могут иметь разные права, и основной целью будет недопущение не просто случайного, а несанкционированного доступа к ресурсу. Если один пользователь не хочет, чтобы задачи другого пользователя имели доступ к ресурсам первого пользователя, то он это должен уметь запретить. Это задача называется ограничение доступа к ресурсам.
Что такое операционная система
Мы получаем три группы задач, которые должна решать операционная система:
- унификация доступа;
- разделение доступа;
- ограничение доступа.
Фактически, это определение операционной системы: операционная система --- это программное обеспечение, которое обеспечивает выполнение трёх указанных задач для того аппаратного обеспечения, на котором эта ОС запущена. Не надо также забывать о том, что наша задача -- повысить удобство работы с компьютером. Ради чего были сделаны операционные системы? Ради того, чтобы человек, который создаёт прикладные программы или их запускает не занимался решением указанных задач самостоятельно и вручную.
Вообще говоря, нет полностью удовлетворительного определения ОС. Более того, если уйти в историю, мы поймём, что пользуемся этим словом неправильно. Operating system -- это не ПО, это систематическое (system) руководство по использованию (operating) компьютера, совокупность методов. Как правило, эти методы программируются и получается программное обеспечение, но смысл термина изначально был именно такой.
Примеры
Из приведённого определения выкинуты подробности отдельных существующих представителей операционных систем. Хотелось бы избежать ситуации, когда под операционной системой понимается нечто c кнопкой "Пуск" в нижнем левом углу экрана. Во-первых, никакого экрана может вообще не быть, поскольку нет графических ресурсов у данной аппаратной платформы (ближайший пример --- домашний ADSL-модем или маршрутизатор). Во-вторых, может быть экран есть, но нету графической кнопки для нажатия на нее мышкой, т.к. может случиться, что эта аппаратная платформа управляется без помощи графических инструментов, а исключительно подачей ей команд, а всякая графика -- прикладная, а не интерфейсная (пример: интерфейс управления самолётом).
Кроме того, термин "ОС" применялся и к сущностям, которые турдно отнести к операционным системам. Приведём пример DOS, всё ещё знакомый многим. Почему DOS -- это не ОС? DOS -- это, дословно, дисковая операционная система, если кто помнит. Многозадачная (в памяти могло быть несколько программ, но без квантования времени и вытеснения задач), а так же однопользовательская. DOS не умеет обеспечивать защиту памяти, со стороны ОС не предоставляются возможности обеспечить даже защиту от случайного, непреднамеренного доступа. Не предоставляет нормальных способов разделения таких ресурсов как видео, аудио, или даже последовательный порт. Для решения этих задача каждый разработчик должен был написать специальную программу-драйвер или, что еще хуже, вписывать в свою программу работу непосредственно с регистрами видеокарты, только после чего всё и начинает работать.
Единственные инструменты по унификации и разделению ресурсов, которые предоставляет DOS пользователю, это файловая система, но она и в те времена вызывала уже много нареканий. Таким образом, DOS содержит только зачатки функций операционной системы. В настоящее время существуют специализированные операционные системы, которые, несмотря на своё название, не выполняют всех поставленных нами задач, поскольку являются компромиссным вариантом и пытаются достигнуть, например, наименьшего времени отклика системы. Все современные ОС общего назначения, в том числе линейка Windows NT, GNU/Linux и BSD-системы вместе с Mac OS X на все поставленные здесь вопросы отвечают полностью утвердительно.
Элементы графической среды пользователя
Поскольку мы имеем дело с многопользовательской системой, перед началом работы мы должны указать системе, от лица какого пользователя будут запускаться последующие процессы. Этот процесс называется идентификацией. Обычно при входе в систему мы вводим имя пользователя и его пароль. При выходе в систему с использованием графического интерфейса имя пользователя можно также выбрать из списка. Имя пользователя (оно же "логин" от англ. login) --- это идентификационная информация, а секретный пароль --- способ подтвердить аутентичность: пользователь именно тот, за кого себя выдает.
Следует отметить, что окно для ввода имени и пароля при старте системы --- только один из возможных способов, которыми пользователь может сообщить системе свои имя или пароль для своей идентификации, и существует множество других способов произвести идентификацию и войти в систему под именем некоторого пользователя.
- В систему можно войти из текстовой консоли, на которую можно переключиться, нажав одну из комбинаций клавиш Alt+F1, .., ALT+F6 (комбинация Alt+А7 переключает на графический интерфейс). Использование текстовой консоли особенно актуально в случае неполадок с графической средой.
- Основным инструментов работы администратора является безопасный удаленный (т.е. по сети с другого компьютера) консольный доступ к системе, используя протокол SSH.
Кроме того, в уже ходе работы пользователь может временно работать под правами другого пользователя. Наиболее типичный случай --- для администрирования системы пользователь может стать суперпользователем, например через команду su - или su <имя пользователя>.
Следует отметить, что в ряде случаев пароль можно не указывать (существуют и другие способы аутентификации), но без сообщения системе имени пользователя обойтись нельзя, хотя в ряде случаев система позволяет войти под заранее заданным пользователем. Например, команда su по умолчанию переключается на суперпользователя root.
Итак, в итоге мы ввели имя пользователя, его пароль и вошли в систему с использованием графической среды. Перед нами рабочий стол, напоминающий рабочий стол, реализованный в Windows. В самом левом нижнем углу экрана по умолчанию находится кнопка, являющаяся аналогом кнопки "Пуск". При ее нажатии которой появляется основное меню, в нем есть подменю для запуска программ, для открытия последних документов, выхода из системы и других задач. Отметим, что программы в меню по умолчанию группируются по своему назначению, а не по фирме-производителю. Меню снабжено строкой поиска, позволяющей найти программы по их названию или назначению (в части версий ПСПО).
К основным визуальным элементам графической среды пользователя также относятся следующие.
- Иконки рабочего стола. Они выполняют примерно ту же функцию, что и пункты меню: при клике на них что-то происходит. Однако в отличие от пунктов меню, которые, как правило, запускают программу, иконки могут делать различные операции, например, открывать корзину, окна доступа к внешним устройства.
- Панель (внизу экрана), которая при желании гибко настраивается --- может быть не на всю ширину экрана, может "уезжать" с экрана, их может быть несколько и так далее. Кроме того, панель может быть заблокирована для исключения случайных изменений в ее внешнем виде. Внутрь панели можно добавлять различные интерфейсные элементы, которые обычно выглядят как кнопки. Есть кнопки обычные, они нужны для быстрого запуска процессов, бывают кнопочки, открывающие свои небольшие меню. К ним относится, например кнопка "Система" в ALT Linux Junior, через которую вы получаете доступ к своим документам, сменным носителям информации и сетевым дискам. Таким образом, наиболее важная задача по какой-то теме запускается одним кликом, программы, использующиеся реже --- двумя кликами. Следующий элемент рабочего стола --- панель задач, на которой показаны запущенные программы.
- В графических средах ПСПО существуют так называемые "апплеты" --- специальные программы, мини-окна которых работают внутри отведённого места на панели, там же они выполняют свои управляющие и информационные задачи. Например, апплетами являются индикатор громкости звука и часы. Вы можете добавлять апплеты на панель или удалить их из панели.
- Одним из важнейших интерфейсных элементов являются виртуальные рабочие столы и их переключатель. Это позволяет размещать открытые окна приложений на разных рабочих столах. Задача, которую решает подсистема виртуальных экранов --- это задача эффективной организации рабочего места. Благодаря виртуальным рабочим столам вы не связаны необходимостью открывать несколько программ, соответствующих разным задачам, в одном пространстве.
Для добавления элементов на рабочий стол и на панель существует особый пункт меню и специальный диалог. Таких элементов в графической среде может быть много, однако для эффективной работы не рекомендуется засорять рабочий стол. Для хранения документов используется папка "Документы", а для быстрого запуска задач -- панель и меню.
Место графической среды пользователя в GNU/Linux
Отметим, что в рассказе об элементах рабочего стола, что мы не использовали слово GNU/Linux, вместо этого использовалось название "графическая среда", То, что видите перед собой в качестве графической среды --- формально говоря, не относится к GNU/Linux вообще. Более того, всё, что мы сейчас рассмотрели, является пользовательским приложениями, в том числе и графическая среда. И даже в рамках ПСПО таких сред две: XFCE в дистрибутиве для слабых машин и KDE в остальных дистрибутивах. И они заметно отличаются, причем не столько визуально, сколько архитектурно. А всего в GNU/Linux может работать около десятка графических сред, причем большая часть из них могут работать и под другими Unix-подобными операционными системами. Это связно с тем, что, в отличие от ОС Windows, здесь по отношению к операционной системе любая графическая среда является именно приложением, некоторой надстройкой над операционной системой.
Стоит отметить, если вы хотите изучить GNU/Linux, то что вам следует делать в последнюю очередь --- изучать досконально возможности графической среды и особенно возможности по ее настройке. Сначала выберите графическую оболочку, которая вам нравится, найдите в ней кнопку запуска эмулятора терминала, разберитесь с GNU/Linux как с операционной системой и набором ее служб, а уже потом настраивайте графическую среду.
Основы использования командной строки
Расскажем теперь об интерфейсе командной строки чуть более формально. Этот интерфейс на самом деле предоставляется специальной программой --- интерпретатором командной строки, называемого также командной оболочкой или "шеллом" (англ. unix shell). Другими словами, это не само ядро Linux с нами "разговаривает", а специальный пользовательский процесс --- один из запускаемых при входе пользователя в систему. По умолчанию это запущенный файл /bin/bash. Чем занимается эта программа? Она читает то, что мы вводим с клавиатуры, анализирует, выполняет соответствующие задачи и выводит результаты --- как свои, так и других программ --- в виде текста. При использовании графической среды для запуска командного интерпретатора следует выбрать пункт Терминал из меню. При использовании среды KDE (Юниор, Мастер) это выглядит так:
Команды для выполнения командной оболочкой могут как вводится с клавиатуры, так и браться из файла, называемого командным сценарием или "скриптом" (англ. shell script). Команды не обязательно исполняются последовательно --- на самом деле командная оболочка является интерпретатором специализированного языка программирования! Отметим, что данная парадигма реализуется не только командной оболочкой: подобный интерфейс имеют, скажем, интерпретатор языка программирования Python, клиент базы данных MySQL и другие программы.
Отдаваемые командному интерпретатору команды обыкновенно вводятся построчно. Каждая строка разбивается на слова в соответствии с простым правилом: последовательность любых символов, идущих подряд и не являющихся разделителями --- это слово, а последовательность разделителей --- промежуток между словами. Разделителями являются пробел, символ табуляции и символ перевода строки, причем последний актуален в качестве разделителя при использовании файлов сценариев, а не в случае ввода с клавиатуры.
Итак, введенная строка разбита на слова. Первое из этих слов считается командой, а все остальные --- параметрами этой команды, пока не встретится слово, являющееся признаком конца команды текущей команды и начала новой или строка не закончится. Откуда взялось такое соглашение? Конечно, можно было на каждый случай жизни придумать специальную команду, но понятно, что слова при таком подходе быстро закончились бы и команды в конце концов стали бы выглядеть довольно странно. Запомнить такой букет было бы, вероятно, совершенно невозможно. Поэтому при работе с командной строкой применяется следующий принцип: команда (обычно это имя утилиты, но об этом далее) решает ту или иную пользовательскую подзадачу, а все параметры этой подзадачи (имена обрабатываемых файлов, нюансы работы) передаются при вводе команды в виде слов.
Вначале введем некоторые общепринятые соглашения. Команда следует после символа "$", который пользователь в видит в конце приглашения к вводу при использовании командного интерпретатора. Например, запись
$ ls
означает, что следует ввести ls и нажать Enter. Если же для выполнения команды должно происходить от лица суперпользователя (root), то перед командной будет выводится символ "#", которым заканчивается приглашение к вводу для пользователя root. Таким образом, команды
$ su - # service network restart
означают выполнение команды переключения пользователей su с параметром "-" (система запросит пароль суперпользователя) и выполнение команды service с параметрами network и restart с праваими суперпользователя.
Рассмотрим следующую команду:
$ #script -t my_script 2> my_script.time
где "$", как уже было сказано, не часть команды, а приглашение ввода. Это пример того, как люди используют список введенных ими команд ("историю") в качестве записной книжки. Дело в том, что введенная в начале строки решетка является специальным символом, обозначающим комментарий. Таким образом, команда была лишь введена, но не выполнена, однако при этом она попала в историю введенных команд (эту историю, разумеется, можно просматривать, например клавишами "вверх" и "вниз"). Представим теперь, что символа комментария в начале строки не стоит:
$ script -t my_script 2> my_script.time
Каким образом будет разобрана такая команда? Интерпретатор выделит имя команды ("script") и два параметра ("-t" и "my_script"). Cлово "2>" в данном случае параметром команды не является: оно содержит символ "больше" (">") и является указанием интерпретатору выполнять перенаправление вывода сообщений об ошибках в файл my_script.time. К моменту запуска команды это слово будет уже обработано интерпретатором (можно считать, что с точки зрения команды script соответствующая группа символов просто исчезнет).
Фактически, диалог пользователя и системы при помощи командной строки происходит следующим образом. Пользователь набирает команду в командной строке, а интерпетатор эту строку обрабатывает. Обратим внимание на три этапа обработки:
Командный интерпретатор определяет, что за команда была введена (в данном случае это script). В командном интерпретаторе есть небольшой набор встроенных (built-in) команд --- чтобы их выполнить, не нужно запускать отдельных программ (хорошим примером является команда cd, изменяющая текущий каталог). Если команда является встроенной, то она будет выполнена самим интерпретатором, в противном же случае он по специальному алгоритму будет вначале искать в файловой системе программу с таким именем.
Командный интерпретатор просматривает строку и ищет в ней специальные управляющие символы. Ранее, когда шла речь об обыкновенных символах и разделителях, мы намеренно допустили некоторую неточность. На самом деле есть и третий тип символов --- управляющие. После того, как интерпретатор находит управляющие символы, он их обрабатывает в соответствии с их значением. В данном случае стандартный вывод (поток) ошибок утилиты script перенаправляется не на терминал, а в файл (сама утилита script этого даже не заметит, если не будет специально "присматриваться").
После того, как вывод будет перенаправлен, этот фрагмент строки будет считаться обработанным ("удалится"), а утилита script будет запущена с двумя параметрами.
Чем же занимается утилита script? Оказывается, она протоколирует все действия, производимые пользователем: записывает в специальный файл вводимые команды и получаемые результаты. Именно эта утилита и использовалась для написания наших примеров.
Заметим теперь, что передаваемые команде параметры обычно логически разбиваются на две группы --- ключи и содержательные параметры. Содержательные параметры --- это имена объектов, строки, специальная информация. Ключи же --- это особого вида параметры, начинающиеся обычно с дефиса ("-"). В силу этого в unix-подобных системах не принято начинать названия файлов с дефиса.
Наличие в командной строке ключей означает, что команда должна выполняться с некоторыми нюансами и изменениями. Ключ -t в нашем случае заставляет утилиту script дополнительно выводить время (-t --- time), содержательный же параметр my_script --- это имя файла, с которым, согласно нашей команде, утилита должна работать. Следует отметить, что командный интерпретатор в данном случае ничего не знает о смысле этих ключей, для него это просто две строки.
Будем теперь рассматривать вместо команды script команду ls (от англ. list), показывающую список файлов в текущем, если не указано иного, каталоге. При выполнении некоторых специальных условий она так же выделяет объекты различных типов различными цветами, но не всегда. Например, если вызвать команду ls не просто как ls, а как /bin/ls то выделения цветом не произойдет:
$ /bin/ls Dir1 file1
Здесь /bin/ls --- это полный путь к соответствующему файлу в дереве каталогов файловой системы, а строка "Dir1 file1" --- это вывод команды /bin/ls, который видит пользователь.
Обратим внимание, что отличить имя файла от имени каталога в выводе ls без раскраски невозможно. Можно, однако, указать ключ -F, который заставит ls после имен каталогов выводить символ "/". Это типичный пример использования ключа, который модифицирует работу программы. Передаваемый параметр не соответствует никакому объекту: это не файл и не имя. С этим ключом, однако, поведение программы несколько изменяется:
$ ls -F Dir1/ file1
Если указать ключ -s, то мы увидим и размер объектов с точки зрения физической организации файлвовой системы. Каталог в данном случае имеет размер 4 блока, а файл --- 0 блоков (он пуст).
$ ls -F -s итого 4 4 Dir1/ 0 file1
Для ключей по возможности соблюдается принцип аббревиативности: вместо полных названий используется одна буква, с названием как-либо связанная. Для ключа -F эта связь неочевидна (от слова classiFy), а вот -s означает size (размер). Принцип аббревиативности нужен вот зачем: когда используется сразу несколько ключей, появляется возможность уменьшить количество набираемых символов. Например, команда ls -F -s и так не слишком длинная, однако ее можно еще сократить, поскольку однобуквенные ключи могут прилипать друг к другу:
$ ls -Fs итого 4 4 Dir1/ 0 file1
Мы ставим один общий дефис, а дальше перечисляем все однобуквенные ключи. Достоинство однобуквенных ключей --- их быстро набирать. Недостатков у них два. Во-первых, не всегда легко запомнить значения всех ключей (смысл сокращений). Отметим, что используются в ключах как маленькие, так и большие буквы. Так, ls с ключом -a (англ. all) показывает все объекты в текущем каталоге:
$ ls -a . .. Dir1 file1 .file1
Как видно, по-умолчанию утилита ls не показывает объекты с именами, начинающимися с точки. Здесь "." и ".." --- ссылки на каталог верхнего уровня и на текущий каталог. Ключ же -A (almost all) заставит вывести "почти все" объекты: будут пропущены "." и ".." (они есть в любом каталоге, и информация о них обычно не нужна):
$ ls -A Dir1 file1 .file1
Второй недостаток однобуквенных ключей состоит в том, что алфавит рано или поздно заканчивается и букв начинает не хватать. Когда ключей много или используются некоторые из них редко, то применяют полнословную нотацию. Ключи в этом случае начинаются с двух дефисов, после которых идет полное название параметра (при этом мы не отступаем от правила, предписывающего ключам начинаться с дефиса). Чаще всего однобуквенные ключи имеют полнословные эквиваленты:
$ ls --all . .. Dir1 file1 .file1 $ ls --almost-all Dir1 file1 .file1
Важно понимать, что описанные принципы работы с ключами --- это всего лишь соглашения, которые, увы, соблюдаются не всеми и не всегда. Никто не мешает создать программу, с ключами не работающую вовсе или использующую другие принципы их написания. Несколько таких программ (dd, ps, tar) были созданы давно, когда этого соглашения не было, а потому передаваемые им параметры выглядят несколько иначе.
Основы использования командной строки
Для чего нужен командный интерпретатор?
Командный интерпретатор (или, на сленге, шелл --- от англ. unix shell) выполняет 3 функции:
- Предоставляет удобные средства для работы с командной строкой. Это, например, просмотр истории команд (клавиши "вверх" и "вниз"), поиск по истории команд (обычно Ctrl+R и Ctrl+S), дополнение команды и ее параметров по нажатию клавиши tab.
Предоставляет возможность комбинировать и интегрировать различные стандартные утилиты. Утилитами на сленге обычно называют небольшие программы из стандартного окружения unix-систем (от англ. util), которые решают свою небольшую задачу, при этом получая данные и выдавая результат в текстовом виде. Перенаправление ввода-вывода позволяет реализовать совместную работу нескольких утилит, и, таким образом, решить некоторую более сложную пользовательскую задачу. Подобное удобство манипулирования утилитами предоставляет только командный интерпретатор, и именно это является его основной функцией.
- И, наконец, командный интерпретатор --- это специализированный высокоуровневый язык программирования, ориентированный на операции с объектами файловой системы.
Переменные
Как в любом языке программирования, в шелле есть переменные. В силу особенностей назначения шелла все переменные в нем являются строковыми (при необходимости в арифметических операциях они временно преобразуются в целочисленные и обратно).
Пример инициализации переменной. Заметьте, что при инициализации переменной до и после знака "=" не должно стоять пробелов, и что для получения значения переменной перед ее именем обязательно ставят символ "$", а имя может быть заключено в фигурные скобки для определенности.
$ VAR="Value Value" $ echo $VAR Value Value $ echo VAR VAR $ echo "Переменная VAR : ${VAR} сейчас" Переменная VAR : Value Value сейчас
Переменные автоматически передаются всем программам, запущенным из шелла, в качестве части окружения созданного процесса операционной системы. Окружение процесса --- это набор достаточно разнообразной информации связанной с процессом. Туда входят, например, текущий каталог, дескрипторы открытых файлов, и т. п. При создании нового процесса путем копирования (fork) окружение практически полностью наследуется.
Некоторые переменные, например HOME или PATH определяются при входе пользователя в систему в запускаемом при входе пользователя интерпретаторе (login shell), и от него наследуются всеми процессами, запущенными пользователем. Переменная PATH содержит список каталогов, в которых шелл ищет исполняемые файлы.
$ echo $PATH /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
Заметим, что в отличие от Windows, DOS и ранних версий UNIX, текущий каталог ("./") по соображениям безопасности в PATH не включен.
Обратим внимание на значения переменных, содержащие пробел. Начнем с того, что при задании такого значения обязательно использование кавычек, иначе пробел будет считаться разделителем между инициализацией переменной и запуском команды:
$ VAR="Value Value" $ echo "$VAR" Value Value $ echo $VAR Value Value
Как видно, при использовании кавычек значение сохраняется в первозданном виде. Без закавычивания несколько пробелов превращаются в один.
Перенаправление ввода вывода
Для работы с файлами прикладные программы используют файловые дескрипторы. Как уже упоминалось, любая запущенная программа (то есть процесс операционной системы) имеет доступ к трем инициализированным перед ее запуском файловым дескрипторам. Они имеют следующие назначение, мнемонические обозначение и номер:
- стандартный поток ввода stdin имеет номер 0;
- стандартный поток вывода stdout имеет номер 1;
- стандартный поток для сообщений об ошибках stderr имеет номер 2.
# и иногда запускающий процесс Все прочие файловые дескрипторы, создаваемые программой, начинаются с номера 3. Подготовкой стандартных файловых дескрипторов занимаются операционная система, а запущенный процесс просто получает уже готовые к использованию дескрипторы и может сразу их использовать для файлового ввода-вывода. По умолчанию все три дескриптора ассоциируются с терминалом: ввод связан с клавиатурным вводом, а вывод и вывод ошибок выводят на экран.
В качестве наглядной демонстрации удобства подобного подхода рассмотрим утилиту cat. Сама по себе она достаточно бессмысленна --- читает данные из stdin и выводит их в stdout. Поэтому, если пользователь при работе с ней наберет на клавиатуре "Hello" и Enter, то именно это слово и будет выведено на экран:
$ cat Hello Hello
При работе с командной средой существует возможность при запуске каждой программы изменить поведение стандартных потоков, например, связав их с файлами. Шелл позволяет сделать это при помощи символов "<" , ">" и ">>", записываемых после параметров команды:
символ "<" перенаправляет стандартный потока ввода;
символ ">" перенаправляет стандартный потока вывода, затирая старое содержимое файла;
символы ">>" перенаправляют стандартный поток вывода, добавляя его содержимое в конец файла-аргумента.
Рассмотрим следующие примеры использования перенаправления ввода-вывода в файл.
$ # Здесь пользователь набирает "Hello" на клавиатуре: $ cat >> File Hello $ # А здесь выводит созданный файл на экран: $ cat < File1 Hello $ # Здесь пользователь набирает "Hello World" на клавиатуре: $ cat >> File1 Hello World $ # И еще раз выводит созданный файл на экран: $ cat < File1 Hello Hello World $ # Записываем "Hello?" в файл, затирая старое содержимое: $ echo "Hello?" > File1 $ cat < File1 Hello? $ # Копируем File1 в File2 через перенаправления ввода-вывода: $ cat < File1 > File2 $ cat File2 Hello?
Перед символами можно указать номер дескриптора для перенаправления. Таким образом, перенаправление стандартного потока ошибок в файл реализуется конструкцией "2>", например:
$ script -t my_script 2> my_script.time
Например, у утилиты cat нет ключа --l, и если попытаться вызвать ее с ним, она выведет диагностическое сообщение в стандартный поток ошибок.
$ cat --l < File1 > File3 2> Error $ cat Error cat: нераспознанный ключ `--l'
Если мы хотим поместить в один файл и сообщения об ошибках, и стандартный вывод программы, то можно использовать конструкцию "&>". Следующая команда поместит в файл File3 сообщение о невозможности прочитать файл /etc/shadow и содержимое файла /etc/passwd.
$ cat /etc/shadow /etc/passwd &> File3
Еще более интересным и многообещающим является возможность ассоциирования стандартного потока вывода одной программы с стандартным потоком ввода другой. В командном интерпретаторе эта операция организуется символом "|" ( для реализации этой функциональности на системном уровне обычно используются безымянные каналы).
Программа cal выводит календарь на месяц. Если с потоком вывода проассоциирован терминал, то cal раскрашивает текущий день. В противном случае выводится просто текст. Например, при вызове cal | cat выделения цветом не будет, так как потоком вывода для cal будет безымянный канал.
$ cal | cat Июль 2008 Вс Пн Вт Ср Чт Пт Сб 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
Утилита wc без параметров выводит количество символов, слов и переводов строк в стандартном потоке ввода.
$ cal | wc 8 40 186
Можно делать более длинные конвейеры, например cal | tac | tac. Утилита tac выводит поступившие ей строки в обратном порядке, так что, если применить её два раза, ничего не произойдёт:
$ cal | tac | tac Июль 2008 Вс Пн Вт Ср Чт Пт Сб 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
Утилита head выводит заданное количество первых строк ввода, tail --- последних. Комбинируя эти утилиты, можно получить произвольный срез файла по строкам):
$ cal | head -2 | tail -1 Вс Пн Вт Ср Чт Пт Сб
Перенаправление --- очень эффективный интрумент, использующийся практически в любом сценарии на языке Shell.
Генерация списка файлов по шаблону
Для групповых операций с файлами командный интерпретатор позволяет использовать регулярные выражения для задания группы файлов. Используется стандартная нотация, поддерживаются диапазоны.
Примеры:
$ # Файлы, начинающиеся с "F": $ ls F* File1 File2 File3 File4 File45 File678 $ # Файлы с именами из "File" и двумя символами после: $ ls File?? File45 $ # "[2-4]" означает диапазон из 2, 3, 4: $ ls File[2-4] File2 File3 File4 $ # ^ означает инверсию, "[^2-4]" --- один символ не из диапазона 2-4: $ ls File[^2-4] File1 $ # "[2-46*]" --- символ 2, 3, 4, 6 или "*": $ ls File[2-46*] File2 File3 File4 $ # "[2-46]*" --- 2, 3, 4 или 6, после которых может идти что угодно: $ ls File[2-46]* File2 File3 File4 File45 File678
При использовании генерации имен файлов в unix-системах не следует забывать, что выполняет ее именно командный интерпретатор, а не вызываемая программа. Это может вызывать неудобства в ряде случаев.
Так же надо обратить внимание, что файлы, имя которых начинается с точки (".") по умолчанию не включаются в генерируемые списки, соответствующие шаблону "*", а под ".*" попадают далеко не всегда нужные каталоги "." и "..":
$ ls .* . .. .FileFile .FileFileFile
Общего удобного решения этой проблемы не существует. В частных случаях можно попробовать воспользоваться исключением:
$ ls .[^.]* .FileFile .FileFileFile $ ls .[^.]* * .FileFile .FileFileFile File1 File2 File3 File4 File45 File678
В качестве еще одного неудобного следствия генерации списков файлов следует отметить то, что программа не может отличить ключ от имени файла:
$ # Cоздаем файл c именем -l $ echo 1 > -l $ ls File1 File2 File3 File4 File45 File678 -l $ # А здесь ls "думает", что ее вызвали с ключом -l: $ ls * -rw-r--r-- 1 user user 1 2008-08-01 08:14 File1 -rw-r--r-- 1 user user 1 2008-08-01 08:15 File2 -rw-r--r-- 1 user user 1 2008-08-01 08:15 File3 -rw-r--r-- 1 user user 1 2008-08-01 08:15 File4 -rw-r--r-- 1 user user 1 2008-08-01 08:15 File45 -rw-r--r-- 1 user user 1 2008-08-01 08:16 File678
Ряд программ, принимающих в качестве аргументов имена файлов, в том числе большинство из состава набора программ coreutils, учитывают эту особенность и позволяют указать специальный аргумент --, который символизирует то, что список опций завершён и все дальнейшие аргументы следует трактовать как имена файлов.
Основы использования командной строки
[suspended]
Здесь мы прекращаем разговор про shell как про интегратор, оставив незатронутыми две очень важные темы, которые напрямую связанны с shell как языком программирования:
- операторы, которые обеспечивают shell алгоритмическую полноту( циклы, условные операторы)
- написание собственных командных сценариев.
Пока что не говорилось про shell в своей первой ипостаси- как удобный инструмент для работы с командной строкой. А между тем грамотно настроенный shell хорошо помогает облегчить работу с командной строкой.
Среди различных удобств, которые предлагает shell, есть, например, подсказка командной строки. Её можно задавать самому, она хранится в переменной окружения PS1. Начнем с простого:
PS1='$ '
Такую подсказку обычно используют в качестве примера во многих книжках по Unix-системам. Теперь давайте сделаем её более разумной. При задании подсказки можно использовать спецпоследовательности, которые при выводе shell будут заменятся значимой информацией. Таких спецпоследовательностей на самом деле довольно много:
\u |
имя пользователя |
\n |
имя хоста до первой точки |
\W |
последняя часть текущего каталога |
\n |
новая строка |
Рассмотрим , например, один из способов отделить начало результата работы команды и подсказку:
PS1="[\[`tput smso`\]\u@\h \W\[`tput rmso`\]]\$ "
Команда tput --- выводит на терминал некую управляющую последовательность которая изменяет режим вывода. Например изменение цвета букв,перестановка курсора в произвольное место и т.д. Это свойства самого терминала. Программа tput всего лишь программный интерфейс к этому свойству. На самом деле практически все программы, которые работают с терминалом, и работают не только с командной строкой, но и со всем экраном пользуются этими свойствами. Что собой являет результат работы программы tput?. Результатом являются символы. Эти символы называются escape-последовательностями или управляющими последовательностям, т.е. для того, чтобы заставить терминал показывать как-то по-другому на него опять таки нужно вывести символы, но это будут уже специальные символы, например, Esc[38m, Esc[0m, которые, вместо того, чтобы отображаться на экране , как-то управляют терминалом, например изменяют цвет вывода. Это пошло с тех времён, когда графических дисплеев не было, а основным устройством управления системой был алфавитно-цифровой терминал, который через последовательное подключение соединялся с компьютером и гонял байты туда-сюда. Когда выяснилось, что было бы неплохо чтобы на этих терминалах можно было хотя бы печатать текст в определенном месте, уж не говоря о различных цветах, стали думать, как можно сделать так, чтобы это устройство, которое по сути аналогично печатной машинке, могло,например, показать буквы другим цветом. Было принято следующее решение - некоторые символы непечатные - при выдаче на экран ничего не происходит, более того, при выдаче этого символа на экран он переходит в режим, когда им управляют, и следующие несколько символов указывают команды. Такая последовательность управляющих символов получила название "управляющая последовательность". В период когда это все разрабатывалось было придумано несколько сотен разных типов терминалов с различными возможностями и управляющими последовательностями. После того как алфавитно-цифровые терминалы вышли из употребления эта ситуация вовсе не стала проще, так как до сих пор существует с дюжину разных программ, которые эмулируют терминал, и у них у всех по-прежнему разные управляющие последовательности. Именно поэтому не стоит запоминать наизусть конкретные управляющие последовательности, а лучше изучить документацию по подсистеме terminfo - база данных информации про терминал- и пользоваться командой tput. Примеры
tput bold |
полужирный |
tput smso |
set mode standout --- наиболее выраженный режим, у разных терминалов он разный. |
Обратите внимание, что командой echo $PS1 нельзя узнать какие именно управляющие последовательности были задействованы, т.к. экран честно выполнит поступившие к нему команды. Самая удобная программа для просмотра --- hexdump с ключом -C
$echo $PS1 | hexdump -C 00000000 5b 5c 5b 1b 5b 37 6d 5c 5d 5c 75 40 5c 68 20 5c |[\[.[7m\]\u@\h \| 00000010 57 5c 5b 1b 5b 32 37 6d 5c 5d 5d 24 0a |W\[.[27m\]]$.| 0000001d
Последний вопрос, который мы рассмотрим - зачем команда tput была обрамлена \[ и \] --- bash рассматривает подсказку весьма примитивно - он считает ширину подсказки суммируя ширину всех её составляющих, после чего считает что подсказка занимает подсчитанное место, а все остальное место --- строка ввода. Но если встречаются управляющие последовательности, то их длина точно также прибавляется к ширине подсказки, однако управляющие последовательности не сдвигают курсор, поэтому у bash формируется неправильное представление о том, где встречается курсор. Специально для этого в PS1 и существуют \[ и \]
Понятие терминала (suspended)
До этого мы воспринимали терминал как нечто само-собой разумеющееся, но на самом деле там есть много возможностей о которых обычно не знают. Мы уже обнаружили такие вещи, как управляющие последовательности терминала. Это с точки зрения терминала как аппаратного устройства. А нет ли особых свойств у терминала как у программной абстракции, почему он имеет название terminal- "конечное устройство"? С точки зрения ОС Linux, терминал это не просто аппаратное устройство, занимающееся передачей байт, он обладает свойством эти байты при передаче преобразовывать. В частности,Когда мы запускали программу cat и потом надо было окончить ввод, мы нажимали Ctrl-D. Если бы это устройство не было бы зарегистрировано в системе как терминал, то ввод Ctrl-D привел бы к тому что программе cat передался бы символ с ASCII кодом 4, и она бы продолжала бы работать. Аналогично с символами Ctrl-C. Здесь мы как раз имеем дело с тем фактом, что при передаче данных посредством терминала эти данные обрабатываются, при чём в обе стороны. В приведенных примерах использованы два вида обработки данных:
- Ctrl-D --- система закрывает для текущей запущенной программы стандартный ввод. Это очень удобно когда программа считывает данные из файла, а скажем с клавиатуры и надо сообщить ей что данные кончились. Первый вид обработка данных -некие манипуляции с системой. Нажатие Ctrl-C приводит к тому что программе посылается сигнал ( короткое сообщение, состоящее только из номера сигнала) который программа должна обработать сама, либо вызовется стандартный обработчик, который в большинстве случаев приводит к завершению программы. Есть отдельная утилита которая и управляет соответствием между нажатиями клавиш и системными манипуляциями- stty.
$ stty -a speed 38400 baud; rows 45; columns 143; line = 0; intr = ^C; quit = ^\; erase = ^?; kill = ^U; eof = ^D; eol = <undef>; eol2 = <undef>; swtch = <undef>; start = ^Q; stop = ^S; susp = ^Z; rprnt = ^R; werase = ^W; lnext = ^V; flush = ^O; min = 1; time = 0; -parenb -parodd cs8 -hupcl -cstopb cread -clocal -crtscts -ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr -igncr icrnl -ixon -ixoff -iuclc -ixany -imaxbel iutf8 opost -olcuc -ocrnl onlcr -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0 isig icanon iexten echo echoe echok -echonl -noflsh -xcase -tostop -echoprt echoctl echoke
Если вы вдруг перевели терминал в режим , в котором он не обрабатывает такого рода последовательности. то например можно применить такую последовательность команд$ stty sane ^J
Почему именно Ctrl-J? - это еще одно свойство т.н. обрабатываемого режима передачи данных в терминале- в свое время бич всех компьютеров и принтеров - сколько символов в конце строки и какие они. В некоторых системах два - "перевод строки" и "возврат каретки". Некоторые используют эти же два символа, но в обратном порядке. Аналогично и с принтерами. В Unix и вслед за ним в Linux поступили просто - сказали что в конце строки стоит символ конца строки. Как вы его определите- такой и будет. Допустим он совпадает с переводом строки. А когда вы выводите это на экран пусть терминал и разбирается. В режиме необрабатываемого ввода никакого преобразования не происходит, поэтому и надо нажимать ^J поскольку он и есть символ "конец строки" - Среди прочих вариантов преобразования ввода\вывода проходящих через терминал есть целых три символа редактирования ввода --- erase(удаление символа), kill(удаление строки), werase(удаление слова) (bs, u, w). Т.е. если вы запустили скажем программу cat то вы можете редактировать её ввод этими тремя символами.
Возвратимся к shell, как к удобному интерфейсу командной строки: разумеется, этих трёх команд недостаточно, поэтому любой уважающий себя shell имеет огромное кол-во команд редактирования ввода. Например, стрелочки вверх\вниз производит просмотр история, а стрелочки влево\вправо отвечают перемещениям курсора по строке. Ctrl-R --- поиск по истории. На самом деле, таких функций --- десятки. Одна из важных возможностей - способ привязать конкретную клавиши\ последовательность к конкретной функции. Это суть команды bind. Именно эта команда определяет для многих программ, привязку клавиш к тем функциям. Эти привязки относятся не к bash как таковому, а к специальной библиотеке readline. Формат таков --- Справа стоит название функции, которую надо вызвать, слева - последовательность клавиш. \C- означает Ctrl, \M- --- meta(эта клавиша присутствует не на всех кдавиатурах)
Идея команды bind --- назначить какие функции редактирования командной строки по нажатию каких клавиш выполнять. Например так делается хождение по словам с помощью PgUp/PgDn:
- bind '"^[[5~": backward-word'
- bind '"^[[6~": forward-word'