Erhalten Sie Zugang zu diesem und mehr als 300000 Büchern ab EUR 5,99 monatlich.
Познакомьтесь со всеми тонкостями работы операционной системы Linux — от системного администрирования до глубинных механизмов, обеспечивающих низкоуровневый функционал Linux. Эта книга, сразу после выхода ставшая бестселлером Amazon, даст вам базовые знания о работе с ядром Linux и принципах правильной эксплуатации компьютерных сетей, о программировании сценариев оболочки и обращении с языком С. Вы изучите вопросы защиты информации, виртуализацию и многое другое. Книга необходима системным администраторам, программистам, специалистам по защите информации, а также всем, кто изучает или хочет изучить Linux максимально быстро и эффективно.
Sie lesen das E-Book in den Legimi-Apps auf:
Seitenzahl: 683
Veröffentlichungsjahr: 2023
Das E-Book (TTS) können Sie hören im Abo „Legimi Premium” in Legimi-Apps auf:
Научный редактор Н. Ланцунцевич
Перевод С. Черников
Брайан Уорд
Внутреннее устройство Linux. 3-е изд.. — СПб.: Питер, 2022.
ISBN 978-5-4461-3946-0
© ООО Издательство "Питер", 2022
Все права защищены. Никакая часть данной книги не может быть воспроизведена в какой бы то ни было форме без письменного разрешения владельцев авторских прав.
Если вы интересуетесь системой Linux, книга «Внутреннее устройство Linux» подойдет вам лучше всего.
LinuxInsider
В книге множество информации практически по всем аспектам архитектуры Linux.
Everyday Linux User
Вы получите полноценное представление о том, что происходит внутри системы, не увязая во множестве деталей. Это отличное дополнение к литературе по Linux.
Фил Булл, соавтор книги Ubuntu Made Easy и член команды по составлению документации для Ubuntu
Автор погружается в глубину операционных систем на базе Linux и рассказывает, как все части системы сочетаются друг с другом.
DistroWatch
Книга заслуживает места на полке суперпользователя Linux.
Журнал The MagPi
Брайан Уорд работает с операционной системой Linux с 1993 года. Кроме этой, он написал книги The Linux Kernel HOWTO, The Book of VMware и The Linux Problem Solver.
Жорди Гутьеррес Эрмосо — профессиональный разработчик и пользователь GNU/Linux с почти двадцатилетним опытом работы, внесший вклад в развитие GNU Octave и Mercurial. В разное время он работал с криптографией, медицинской визуализацией и в сфере экологии — везде на Linux. Когда Жорди не сидит за компьютером, то занимается плаванием, математикой и вязанием.
Петрос Кутупис в настоящее время старший инженер по производительности программного обеспечения в компании HPE (ранее Cray Inc.) в подразделении Lustre High Performance File System. Он создатель RapidDisk Project (www.rapiddisk.org) и занимается его сопровождением. Петрос более десяти лет работает в индустрии хранения данных и помог внедрить многие современные технологии.
Вклад в эту книгу внесли не только те, кто участвовал в процессе ее создания, но и те, без кого я бы ничего не узнал о Linux, а именно: Джеймс Дункан, Дуглас Н. Арнольд, Билл Феннер, Кен Хорнстайн, Скотт Диксон, Дэн Эрлих, Феликс Ли и Грегори П. Смит. За помощь в работе над предыдущими изданиями благодарю Кароля Хурадо, Лорел Чун, Серену Янг, Элисон Лоу, Райли Хоффмана, Скотта Шварца, Дэна Салли, Доминика Пулена, Дональда Кейрона и Джину Стил.
В подготовке третьего издания участвовали Барбара Куин, Рэйчел Монаган, Джилл Франклин, Ларри Уэйда, Хорди Гутьерреса Эрмосо и Петрос Кутуписа. Билл Поллок, основатель издательства No Starch Press, сыграл особую роль в создании этой книги с ее первого издания. И еще раз благодарю Синьцзю Сие за то, что вытерпел меня и в этот раз.
Операционная система не должна быть загадкой. Любому специалисту хочется использовать свое программное обеспечение по желанию, без магических заклинаний или ритуалов. Чтобы этого добиться, необходимо понимать, что делает программное обеспечение и как оно работает, и именно этому посвящена данная книга. Больше вам никогда не придется сражаться со своим компьютером.
Linux — отличная платформа для обучения, так как она ничего не пытается скрыть от пользователя. Большинство сведений о конфигурации системы можно найти в легкочитаемых текстовых файлах. Единственная сложность — выяснить, какие части за что отвечают и как они все сочетаются друг с другом.
Интерес к устройству Linux затрагивает разные сферы жизни. Профессионалы в сфере DevOps и разработчики должны знать почти всю информацию, которая рассматривается в этой книге. Архитекторы и разработчики программного обеспечения Linux также должны знать это, чтобы пользоваться операционной системой наилучшим образом. Для исследователей и студентов, часто работающих в своих собственных системах Linux, будет полезно узнать, почему в системе все устроено именно так, а не иначе, что и рассказывается в книге. Кроме того, есть еще и любители — люди, которые просто проводят время за своими компьютерами ради развлечения, выгоды или и того и другого сразу.
Хотите знать, почему одни вещи работают, а другие нет? Вам интересно, что произойдет, если что-либо изменить? Если вы ответили «Да!», то вы, скорее всего, любитель и найдете ответы на свои вопросы в этой книге.
Требуемый уровень знаний
Вам необязательно быть программистом, чтобы прочитать эту книгу. Понадобятся только базовые навыки пользователя компьютера: вы должны ориентироваться в графическом интерфейсе (особенно в интерфейсе установки и настроек для дистрибутива Linux) и знать, что такое файлы и каталоги (папки). Кроме того, будьте готовы искать и проверять дополнительную документацию в вашей системе и в интернете. И самое главное — быть готовыми исследовать свой компьютер.
Когда речь идет о технических предметах, донести все необходимые знания, — непростая задача. С одной стороны, читатель увязает в излишних подробностях и с трудом усваивает суть, поскольку человеческий разум просто не может одновременно обработать большое количество новых понятий. С другой — отсутствие подробностей приводит к тому, что читатель получает лишь смутное представление о предмете и не готов к усвоению дальнейшего материала.
В этой книге я упростил изложение и структурировал материал. В большинстве глав важная информация, которая необходима для дальнейшей работы, предлагается в первую очередь. По мере чтения главы вы встретите в ней и дополнительный материал. Надо ли вам сразу усваивать эти частности? В большинстве случаев полагаю, что нет. Если ваши глаза начинают тускнеть при виде большого количества подробностей, относящихся к только что изученному материалу, не раздумывая переходите к следующей главе или сделайте перерыв. Вас ожидают другие важные вещи.
Для работы вам понадобится компьютер с операционной системой Linux. Возможно, вы предпочтете виртуальную установку — для проверки большей части материала данной книги я пользовался приложением VirtualBox. Вы должны обладать правами доступа superuser (root), хотя основную часть времени следует использовать учетную запись обычного пользователя. Вы будете работать главным образом в командной строке, окне терминала или в удаленном сеансе. Если вы нечасто работали в этой среде, ничего страшного, в главе 2 вы узнаете об этом подробнее.
Как правило, команды будут выглядеть следующим образом:
$ ls /
[some output]
Вводите текст, который выделен жирным шрифтом; обычным шрифтом показан ответный текст, который выдаст машина. Символ $ является приглашением для пользователя с обычной учетной записью. Если вы увидите в качестве приглашения символ #, следует работать в учетной записи superuser (подробнее об этом в главе 2).
Я сгруппировал главы книги в три основные части. Первая часть — вводная, дает представление о системе в целом, а затем предлагается ряд практических заданий с инструментами, которые понадобятся вам для дальнейшей работы в системе. Далее вы детально изучите каждую часть системы, начиная с управления оборудованием и заканчивая конфигурацией сети, следуя обычному порядку запуска системы. И наконец, вы познакомитесь с частями работающей системы, освоите необходимые навыки и рассмотрите инструменты, которые используют программисты.
В большинстве первых глав (кроме главы 2) активно задействовано ядро системы Linux, но по мере продвижения по книге вы будете работать и в своем пространстве пользователя. Если вы не понимаете, о чем я сейчас говорю, не беспокойтесь, объяснения будут даны в главе 1.
Материал излагается по возможности без привязки к какому-либо дистрибутиву системы. Было бы скучно описывать все варианты системы, поэтому я попытался рассказать о двух основных семействах дистрибутивов: Debian (включая Ubuntu) и RHEL/Fedora/CentOS. Кроме того, я описал настольные и серверные установки. Значительный объем материала можно использовать во встроенных системах, таких как Android и OpenWRT, но поиск различий между ними предоставляется вам.
Второе издание вышло в переходный период для всех систем Linux. Часть традиционных компонентов постепенно изменялась, что затрудняло изучение, потому что читатели сталкивались с большим разнообразием настроек. Однако сейчас новые элементы (в частности, systemd) надежно заняли свои места в системах, поэтому я смог значительно упростить и сократить материал по этой теме.
Я все так же сохранил акцент на роли ядра в системе Linux. Именно эта информация была наиболее интересна читателям, и вы сами, скорее всего, взаимодействуете с ядром чаще, чем думаете.
В новом издании появилась глава о виртуализации. Несмотря на то что Linux часто устанавливают именно через виртуальные машины (например, через облачные серверы), подобный способ виртуализации выходит за рамки данной книги. Все потому, что система работает на виртуальной машине практически так же, как на «голом» железе. Таким образом, информация об этом отличается в основном лишь терминологией. Кроме того, со времени выхода второго издания контейнеризация стала более популярной, поэтому я добавил информацию и о ней, ведь контейнеры в основном состоят из множества функций Linux, которые описаны в книге. В контейнерах часто используются контрольные группы cgroups, о которых я также рассказываю в третьем издании. В книгу в том числе добавлены сведения о менеджере логических томов, системе ведения журнала journald и протоколе Ipv6 (в главе 9).
Мне хотелось снабдить вас сведениями, которые понадобятся для быстрого начала работы. Их усвоение потребует некоторых усилий, однако я не намереваюсь делать из вас «тяжелоатлетов», чтобы вы смогли одолеть эту книгу. Когда вы будете понимать важнейшие моменты, изложенные здесь, для вас не составит труда отыскать подробности и разобраться в них.
Я удалил кое-какие исторические детали, которые были в первом издании. Если вы интересуетесь системой Linux и ее отношением к истории системы Unix, обратитесь к книге Питера Салуса The Daemon, the Gnu, and the Penguin (Reed Media Services, 2008) — в ней рассказано о том, как развивалось используемое нами программное обеспечение.
До сих пор ведутся споры о наименованиях некоторых элементов операционных систем. Они затрагивают даже само название системы Linux — как она должна называться: Linux или же GNU/Linux (чтобы отразить применение некоторых элементов проекта GNU)? В книге я старался использовать самые распространенные и по возможности наименее громоздкие названия.
Ваши замечания, предложения, вопросы отправляйте по адресу [email protected] (издательство «Питер», компьютерная редакция).
Мы будем рады узнать ваше мнение!
На веб-сайте издательства www.piter.com вы найдете подробную информацию о наших книгах.
На первый взгляд такая современная операционная система, как Linux, очень сложна и состоит из невероятного количества инструментов, которые работают и взаимодействуют друг с другом одновременно. Например, веб-сервер может взаимодействовать с сервером базы данных, который, в свою очередь, может применять разделяемую библиотеку, используемую многими другими программами. Как же все это работает и какой во всем этом смысл?
Самый эффективный способ понять, как работает операционная система, — абстрагироваться от большинства деталей, составляющих часть, которую вы изучаете, и сосредоточиться на ее основной цели и функциональности. Например, когда вы едете в автомобиле, вам не нужно думать о таких деталях, как крепежные болты, которые удерживают двигатель внутри него, или о людях, которые строят и ремонтируют дорогу, по которой он едет. Все, что вам действительно нужно знать, — это цель автомобиля (перевезти вас куда-то) и основные знания о том, как им пользоваться (например, как открывать дверь и пристегивать ремень безопасности).
Подобный уровень абстрагирования сработает, если вы просто пассажир в машине. Но если вы управляете автомобилем, вам нужно копнуть глубже и разбить свою абстракцию на несколько частей. Вы должны расширить свои знания в трех областях: сам автомобиль (например, его размер и возможности), манипуляции его частями (рулевое колесо, педаль акселератора и т.д.) и особенности дороги.
Абстрагирование от деталей может помочь при попытке найти и устранить проблемы. Предположим, что вы ведете машину и поездка дается тяжело. Вы можете быстро оценить три основные упомянутые абстракции, связанные с автомобилем, чтобы определить источник проблемы. Если с первыми двумя абстракциями все в порядке (ваш автомобиль и способ вождения) и ни одна из них не является проблемой, можете сузить проблему до самой дороги. В таком случае выясняется, что дорога ухабистая. Теперь, если нужно, вы можете копнуть глубже в абстракцию дороги и подумать, почему ее состояние ухудшилось или, если она новая, почему строители так паршиво сделали свою работу.
Разработчики программного обеспечения используют абстракцию в качестве инструмента при создании операционной системы и ее приложений. В программном обеспечении существует множество терминов для абстрактного разделения, включая «подсистему», «модуль» и «пакет», но в этой главе мы будем применять термин «компонент», потому что так проще. При создании программного компонента разработчики обычно не задумываются о внутренней структуре других компонентов, но рассматривают те из них, которые могут задействовать (чтобы не приходилось писать дополнительное ненужное программное обеспечение), и размышляют о том, как их использовать.
В этой главе мы подробно рассмотрим компоненты, составляющие систему Linux. Хотя каждый из них имеет огромное количество технических деталей, сейчас не будем брать их в расчет и сосредоточимся на том, что именно компоненты делают по отношению ко всей системе. А детали рассмотрим в последующих главах.
Использование абстракции для разделения вычислительных систем на компоненты облегчает понимание, но не работает без организации процессов. Мы объединяем компоненты в слои или уровни классификации (или группы) в соответствии с тем, где они находятся между пользователем и оборудованием. Веб-браузеры, игры и т.п. находятся на верхнем уровне, на нижнем располагается память в компьютерном оборудовании — нули и единицы. Операционная система занимает множество промежуточных уровней.
Система Linux имеет три основных уровня. На рис. 1.1 показаны эти уровни и компоненты внутри каждого из них. Аппаратное оборудование компьютера (hardware) находится на базовом уровне. Оно включает в себя память и один или несколько процессоров (CPU) для выполнения вычислений, а также для чтения из памяти и записи в нее. Такие устройства, как диски и сетевые интерфейсы, — тоже часть аппаратного оборудования.
Следующий уровень — это ядро (kernel), основа операционной системы. Ядро — это программное обеспечение, содержащееся в памяти. Оно сообщает процессору, где находится его следующая задача. Выступая в качестве посредника, ядро управляет оборудованием (особенно оперативной памятью) и является основным интерфейсом между оборудованием и любой запущенной программой.
Рис. 1.1. Основные компоненты системы Linux
Процессы (processes) — запущенные программы, которыми управляет ядро, — в совокупности составляют верхний уровень системы, называемый пользовательским пространством (user space). (Более конкретный термин для процесса — «пользовательский процесс» (user process), независимо от того, взаимодействует ли пользователь непосредственно с процессом. Например, все веб-серверы работают как пользовательские процессы.)
Существует огромная разница между тем, как работает ядро и пользовательские процессы: ядро работает в режиме ядра (kernel mode), а пользовательские процессы — в пользовательском режиме. Код, работающий в режиме ядра, имеет неограниченный доступ к процессору и оперативной памяти. Такая мощная, но опасная привилегия позволяет легко повредить ядро и вывести из строя всю систему. Область памяти, доступ к которой может получить только ядро, называется пространством ядра (kernel space).
Пользовательский же режим ограничен доступом к подмножеству памяти (обычно довольно небольшому) и безопасным операциям процессора. Пользовательское пространство — это части основной памяти, к которым могут получить доступ пользовательские процессы. Если процесс совершает ошибку и выходит из строя, последствия локальны и устраняются с помощью ядра. Это означает, что если ваш веб-браузер выйдет из строя, он не будет продолжать научные вычисления, которые выполнялись в фоновом режиме в течение нескольких дней.
Теоретически, пользовательский процесс, вышедший из строя, не может нанести серьезного ущерба остальной части системы. На самом деле это зависит от того, что вы считаете серьезным ущербом, а также от особых привилегий процесса, ведь некоторым процессам разрешено делать больше, чем другим. Например, может ли пользовательский процесс полностью уничтожить данные на диске? Если имеет необходимые привилегии — да, и это довольно опасно. Однако существуют меры предосторожности, и большинству процессов просто не разрешается сеять хаос в системе.
Примечание
Ядро Linux может запускать потоки ядра (kernel threads), очень похожие на процессы, но имеющие доступ к пространству ядра, например kthreadd и kblockd.
Оперативная память — это, пожалуй, самый важный элемент оборудования компьютерной системы. В своей первоначальной форме оперативная память — это просто огромная область хранения для группы нулей и единиц. Каждый слот для нуля или единицы называется битом. Именно в оперативной памяти хранятся запущенные ядро и процессы — по сути, тоже большие наборы битов. Все входные и выходные данные с периферийных устройств проходят через оперативную память также в виде набора битов. Процессор — это оператор памяти, он считывает свои инструкции и данные из памяти и записывает данные обратно в память.
В отношении памяти, процессов, ядра и других частей компьютерной системы часто используется термин «состояние» (state). Строго говоря, состояние — это особое расположение битов. Например, если у вас есть четыре бита в памяти, то биты 0110, 0001 и 1011 представляют три разных состояния системы.
Если учесть, что один процесс может легко состоять из миллионов битов в памяти, то когда речь идет о состояниях, проще использовать абстрактные термины. Вместо того чтобы описывать состояние с помощью битов, процесс описывают как завершенный или происходящий в данный момент. Например, вы можете сказать: «Процесс ожидает ввода» или «Процесс находится на втором этапе запуска».
Примечание
Поскольку принято ссылаться на состояние в абстрактных терминах, а не на фактические биты, термин «образ» (image) относится к определенному физическому расположению битов.
Почему мы говорим об оперативной памяти и состояниях? Почти все, что делает ядро, связано с оперативной памятью. Одной из задач ядра является разделение памяти на множество областей, и оно должно постоянно отслеживать определенную информацию об их состоянии. Каждый процесс получает некоторую часть памяти, и ядро должно обеспечивать необходимое количество памяти для каждого из процессов. Ядро отвечает за управление задачами в четырех основных областях системы.
• Процессы. Ядро определяет, каким процессам разрешено использовать процессор.
• Память. Ядро должно отслеживать распределение памяти: сколько в данный момент выделено конкретному процессу, сколько можно разделить между другими процессами и сколько свободно.
• Драйверы устройств. Ядро действует как интерфейс между оборудованием (например, диском) и процессами. Обычно оно управляет подключенным оборудованием.
• Системные вызовы и поддержка. Процессы обычно используют системные вызовы для связи с ядром.
Далее мы кратко изучим каждую из этих областей.
Примечание
Если вы хотите изучить работу ядра более подробно, то я советую прочитать две отличные книги на эту тему: десятое издание книги Ави Зильбершаца Operating System Concepts (Wiley, 2018) и четвертое издание книги Эндрю Таненбаума Modern Operating Systems (Prentice Hall, 2014).
Управление процессами описывает запуск, приостановку, возобновление, планирование и завершение процессов. Концепции, лежащие в основе запуска и завершения процессов, довольно просты, но описание того, как процессом используется процессор, немного сложнее.
В любой современной операционной системе многие процессы выполняются параллельно. Например, у вас могут быть открыты веб-браузер и электронная таблица одновременно. Однако все не так, как кажется: процессы, стоящие за этими приложениями, обычно не выполняются в одно и то же время.
Рассмотрим систему с одноядерным процессором. Многие процессы могут задействовать процессор, но только один из них фактически использует процессор в любой момент времени. На практике процесс работает с процессором в течение небольшой доли секунды и делает паузу, затем другой процесс занимает процессор в течение еще одной небольшой доли секунды, потом в дело вступает еще один процесс и т.д. Акт передачи одним процессом управления процессором другому процессу называется переключением контекста.
Каждый отрезок времени, называемый квантом времени, позволяет процессу выполнить значительные вычисления (и действительно, процесс часто завершает свою задачу в течение одного кванта времени). Однако из-за того, что кванты очень малы, пользователи их не воспринимают, и возникает ощущение, что система выполняет несколько процессов одновременно (режим многозадачности).
Ядро отвечает за переключение контекста. Чтобы понять, как это работает, рассмотрим ситуацию, в которой процесс работает в пользовательском режиме, но его временной квант истек. Вот что происходит.
1. Процессор (фактическое оборудование) прерывает текущий процесс на основе внутреннего таймера, переключается в режим ядра и передает управление обратно ядру.
2. Ядро записывает текущее состояние процессора и памяти, что необходимо для возобновления только что прерванного процесса.
3. Ядро выполняет любые задачи, которые могли возникнуть в течение предыдущего временного кванта (например, сбор данных из ввода-вывода).
4. Теперь ядро готово к запуску другого процесса. Оно анализирует список процессов, готовых к запуску, и выбирает один из них.
5. Ядро подготавливает память для нового процесса, а затем готовит к нему процессор.
6. Ядро сообщает процессору длительность временного кванта для нового процесса.
7. Ядро переключает процессор в пользовательский режим и передает управление процессором процессу.
Переключение контекста позволяет понять, когда именно запускается ядро. Суть заключается в том, что ядро запускается между временными квантами процесса во время переключения контекста.
В случае многопроцессорной системы, как и в большинстве современных машин, все немного сложнее, потому что ядро не перестает управлять текущим процессором, чтобы позволить процессу работать на другом процессоре, и одновременно могут выполняться несколько процессов. Но чтобы максимально задействовать все доступные процессоры, ядро в любом случае выполняет необходимые шаги (и может использовать определенные лазейки, чтобы занять больше времени процессора для себя).
Ядро должно управлять памятью во время переключения контекста, а это довольно сложная задача. Должны выполняться следующие условия.
• Ядро должно иметь в памяти выделенную область, к которой пользовательские процессы не могут получить доступ.
• Каждому пользовательскому процессу необходима собственная область памяти.
• Один пользовательский процесс не может получить доступ к области памяти, выделенной другому процессу.
• Пользовательские процессы могут совместно работать с памятью.
• Часть памяти пользовательских процессов может быть доступна только для чтения.
• Система может использовать больше памяти, чем ее существует физически, задействуя дисковое пространство в качестве вспомогательного механизма.
К счастью для ядра, оно не одно выполняет всю работу. Современные процессоры включают в себя блок управления памятью (memory management unit, MMU), который обеспечивает схему доступа к памяти, называемую виртуальной памятью. При использовании виртуальной памяти процесс не получает прямого доступа к памяти через ее физическое местоположение в компьютерной системе. Вместо этого ядро настраивает каждый процесс, чтобы он действовал так, будто ему доступна вся система. Когда процесс обращается к части своей памяти, MMU перехватывает обращение и с помощью таблицы соответствий преобразует адрес памяти с точки зрения процесса в фактическое физическое местоположение памяти в системе. Ядро по-прежнему должно инициализировать, постоянно поддерживать и изменять таблицу соответствий адресов памяти. Например, во время переключения контекста ядро должно заменить таблицу соответствий исходного процесса на таблицу последующего процесса.
Примечание
Реализация таблицы соответствий адресов памяти называется таблицей страниц.
Подробнее о том, как отслеживать производительность памяти, описано в главе 8.
Роль ядра в работе с устройствами относительно проста. Устройство обычно доступно только в режиме ядра, поскольку неправильный доступ (например, пользовательский процесс, запрашивающий отключение питания) может привести к сбою системы. Значительная проблема заключается в том, что различные устройства редко имеют один и тот же интерфейс программирования, даже если устройства выполняют одну и ту же задачу (например, две разные сетевые карты). Поэтому драйверы устройств традиционно являются частью ядра, и они стремятся представить единый интерфейс для пользовательских процессов, чтобы упростить работу разработчика программного обеспечения.
Существует несколько других функций ядра, доступных пользовательским процессам. К примеру, системные вызовы (system calls, syscalls) выполняют определенные задачи, которые сам по себе пользовательский процесс выполнить не может. Например, все действия по открытию, чтению и записи файлов связаны с системными вызовами.
Два системных вызова, fork() и exec(), важны для понимания того, как запускаются процессы.
• fork() — когда процесс вызывает fork(), ядро создает почти идентичную копию процесса.
• exec() — когда процесс вызывает exec(program), ядро загружает и запускает программу program, заменяя текущий процесс.
Все новые пользовательские процессы в системе Linux, за исключением процесса init (см. главу 6), запускаются в результате вызова fork(), и в большинстве случаев exec() применяется для запуска новой программы вместо запуска копии существующего процесса. Возьмем простой пример — любую программу, которую вы запускаете в командной строке, например, команду ls, предназначенную для отображения содержимого каталога. Когда вы вводите ls в окно терминала, оболочка, работающая внутри этого окна, вызывает fork() для создания копии оболочки, а затем новая копия оболочки вызывает exec(ls) для запуска команды ls. На рис. 1.2 показана последовательность исполнения процессов и системных вызовов для запуска команды ls.
Рис. 1.2. Запуск нового процесса
Примечание
Системные вызовы обычно обозначаются круглыми скобками. В примере на рис. 1.2 процесс, запрашивающий ядро для создания другого процесса, должен выполнить системный вызов fork (). Использование круглых скобок зависит от того, как именно вызов будет описан на языке программирования С. Вам не нужно знать язык С, чтобы понять эту книгу, просто помните, что системный вызов — это взаимодействие между процессом и ядром. Кроме того, книга упрощает некоторые группы системных вызовов. Например, exec() относится ко всему семейству системных вызовов, которые выполняют одну и ту же задачу, но различаются по способу программирования. Существует также вариант процесса, называемый потоком, который мы рассмотрим в главе 8.
Ядро поддерживает пользовательские процессы с функциями, отличными от традиционных системных вызовов, наиболее распространенными из которых являются псевдоустройства. Они выглядят как устройства для пользовательских процессов, но реализуются исключительно в программном обеспечении. Это означает, что технически их не должно быть в ядре, но обычно они там присутствуют из практической необходимости. Например, устройство генератора случайных чисел ядра (/dev/random) было бы трудно безопасно реализовать с помощью пользовательского процесса.
Примечание
Технически пользовательский процесс, который обращается к псевдоустройству, должен задействовать системный вызов, чтобы открыть устройство, поэтому процессы не могут полностью избежать применения системных вызовов.
Как уже упоминалось, оперативная память, выделяемая ядром для пользовательских процессов, называется пользовательским пространством. Поскольку процесс — это просто состояние (или образ) в памяти, пользовательское пространство соответствует и всем запущенным процессам в памяти. (Для обозначения пользовательского пространства применяется также более неформальный термин userland, иногда он означает программы, запущенные в пользовательском пространстве.)
Большая часть реальных действий в системе Linux происходит в пользовательском пространстве. Хотя все процессы, по существу, одинаковы для ядра, они выполняют разные задачи для пользователей. Существует элементарная структура уровней (или слоев) обслуживания для различных типов системных компонентов, которые представляют пользовательские процессы. На рис. 1.3 показано, как примерный набор компонентов сочетается и взаимодействует в системе Linux. Основные службы находятся на нижнем уровне (ближе всего к ядру), служебные — посередине, а приложения, с которыми соприкасаются пользователи, — сверху. Рисунок 1.3 представляет собой значительно упрощенную схему, поскольку отображает только шесть компонентов, но на ней видно, что компоненты вверху находятся ближе всего к пользователю (пользовательский интерфейс и браузер), компоненты на среднем уровне включают сервер кэширования доменных имен, используемый веб-браузером, и есть несколько меньших компонентов снизу.
Рис. 1.3. Типы процессов и их взаимодействие
Нижний уровень, как правило, состоит из небольших компонентов, которые выполняют отдельные несложные задачи. На среднем уровне находятся более крупные компоненты, такие как службы почты, печати и баз данных. Наконец, компоненты на верхнем уровне выполняют сложные задачи, которыми пользователь часто управляет напрямую. Кроме того, одни компоненты используют другие. Как правило, если один компонент хочет использовать другой, то последний находится либо на том же уровне обслуживания, либо на уровень ниже.
Рисунок 1.3 лишь приблизительно показывает, как организовано пользовательское пространство. На самом деле в нем нет никаких правил. Например, основная масса приложений и служб записывают диагностические сообщения в логи (logs). Большинство программ задействуют для этого стандартную службу логирования syslog, но некоторые предпочитают писать логи самостоятельно.
Кроме того, некоторые компоненты пользовательского пространства трудно классифицировать. Серверные компоненты, такие как веб-серверы и серверы баз данных, можно считать приложениями очень высокого уровня, так как они выполняют сложные задачи, поэтому их можно поместить на верхний уровень в схеме, изображенной на рис. 1.3. Однако пользовательские приложения могут зависеть от этих серверов, так что такие компоненты можно разместить и на среднем уровне.
Ядро Linux поддерживает традиционную концепцию пользователя Unix. Пользователь (user) — это сущность, которая может запускать процессы и владеть файлами. Чаще всего он ассоциируется с именем пользователя (username), например, в системе может быть пользователь с именем billyjoe. Однако ядро не управляет именами пользователей, оно лишь идентифицирует пользователей с помощью простых числовых идентификаторов пользователей (user ID, UID). (Подробнее о соответствии имен пользователей их идентификаторам вы узнаете в главе 7.)
Пользователи существуют в основном для поддержки прав и границ в системе. Каждый процесс пользовательского пространства имеет владельца (owner) и, как говорят, выполняется от его имени. Пользователь может прекратить свои процессы или изменить их поведение (в определенных пределах), но не может вмешиваться в процессы других пользователей. Кроме того, пользователи могут владеть файлами и выбирать, делиться ли ими с другими пользователями.
Система Linux обычно имеет несколько пользователей в дополнение к тем, которые соответствуют реальным пользователям. Подробнее об этом написано в главе 3, однако уже сейчас нужно знать о самом важном пользователе — суперпользователе(superuser, root). Суперпользователь — это исключение из рассмотренных ранее правил, поскольку он может завершить и изменить процессы других пользователей и получить доступ к любому файлу в локальной системе. Человек, который может действовать как суперпользователь, то есть имеет корневой доступ (root access), считается администратором в традиционной системе Unix.
Примечание
Работа в системе в качестве суперпользователя может быть опасной. Трудно бывает выявить и исправить ошибки, потому что система позволит вам делать все, что угодно, даже если это навредит ей. По этой причине разработчики систем стараются сделать подобный доступ как можно более ненужным: например, система не требует корневого доступа для переключения между беспроводными сетями на ноутбуке. Кроме того, как бы ни был силен суперпользователь, он по-прежнему задействует пользовательский режим операционной системы, а не режим ядра.
Группы (groups) — это наборы пользователей. Основная цель групп — позволить пользователю получать доступ к файлам совместно с другими членами группы.
Мы рассмотрели, что представляет собой работающая система Linux. Пользовательские процессы образуют среду, с которой вы непосредственно взаимодействуете, ядро управляет процессами и оборудованием. И ядро, и процессы находятся в памяти.
Это важная информация, но ее недостаточно: нельзя узнать подробности о системе Linux, не углубившись в нее и «не запачкав руки». В следующей главе мы начнем путешествие в глубины Linux с рассмотрения основ пользовательского пространства. Попутно вы узнаете о важной части системы Linux, которая не обсуждалась в этой главе, — долговременное хранилище (диски, файлы и т.п.). В конце концов, вам же нужно где-то хранить свои программы и данные, верно?
В этой главе мы разберем основные команды и утилиты Unix, с которыми вы будете сталкиваться на протяжении всей книги. Эта информация начального уровня, и вам, возможно, уже известна большая ее часть. Даже если вам кажется, что вы все знаете, потратьте несколько минут на то, чтобы пролистать главу и убедиться в этом, особенно это касается темы иерархии каталогов в разделе 2.19.
Вы можете задать вопрос: «Почему же команды Unix? Разве это не книга о том, как работает Linux?» Это так, но Linux — это разновидность Unix. В этой главе слово «Unix» будет появляться чаще, чем «Linux», а все, что вы узнаете, относится также к системам BSD и другим, основанным на Unix-системе. Я постарался уменьшить количество расширений пользовательского интерфейса, специфичных для Linux, не только для того, чтобы дать основы для применения других операционных систем, но и потому, что эти расширения, как правило, нестабильны. Вы сможете гораздо быстрее адаптироваться к новым версиям Linux, если будете знать основные команды. Кроме того, знание этих команд поможет вам лучше понять ядро, так как многие из них непосредственно соответствуют системным вызовам.
Примечание
Чтобы больше узнать о системе Unix, прочитайте книги для начинающих пользователей: второе издание книги The Linux Command Line (No Starch Press, 2019), второе издание книги Пола Абрахама UNIX for the Impatient (Addison-Wesley Professional, 1995), а также пятое издание книги Learning the UNIX Operating System (O’Reilly, 2001).
Оболочка (shell) — одна из самых важных частей системы Unix. Это программа, выполняющая команды, которые пользователи вводят в окно терминала. Эти команды могут быть другими программами или встроенными функциями оболочки. Оболочка — это еще и среда программирования. Программисты Unix часто разбивают типичные задачи на более мелкие компоненты и применяют оболочку для управления ими.
Многие важные части системы на самом деле являются сценариями (скриптами, shell scripts) оболочки — текстовыми файлами, которые содержат последовательность команд. Если раньше вы работали с системой MS-DOS, вы можете думать о скриптах оболочки как о мощных .BAT-файлах. Поскольку скрипты важны для работы системы, вся глава 11 полностью посвящена им.
По ходу книги вы будете пополнять свои знания о том, как обращаться с командами с помощью оболочки. Одно из важных ее преимуществ состоит в том, что если вы допустили ошибку, то можете увидеть, какой текст набрали, исправить ошибку, а затем повторить снова.
Существует множество различных оболочек Unix, но все они — производные от оболочки Bourne shell (/bin/sh), стандартной оболочки, разработанной в компании Bell Labs для ранних версий Unix. Любая система Unix требует ту или иную версию Bourne shell для корректной работы, что будет показано на протяжении всей этой книги.
Система Linux использует расширенную версию оболочки Bourne под названием bash, или Bourne-again. Оболочка bash — это оболочка по умолчанию в большинстве дистрибутивов Linux, и каталог /bin/sh обычно указывает на bash в системе Linux. Для выполнения заданий из книги необходимо использовать оболочку bash.
Примечание
Оболочка bash может быть не установлена в качестве оболочки по умолчанию, если вы пользуетесь этой главой как руководством для работы с системой Unix в организации, где не являетесь системным администратором. Вы можете изменить свою оболочку с помощью команды chsh или обратиться за помощью к системному администратору.
После установки системы Linux необходимо создать как минимум одного обычного пользователя для своей личной учетной записи. В этой главе зайдите в систему как обычный пользователь.
После входа в систему откройте окно оболочки (часто называется терминалом). Самый простой способ — войти с помощью графического интерфейса, такого как Gnome или KDE, — открыть приложение Terminal, которое запускает оболочку внутри нового окна. После того как вы откроете оболочку, в верхней части окна появится подсказка, которая обычно заканчивается знаком доллара ($). В системе Ubuntu это приглашение должно выглядеть следующим образом: name@host:path$, а в Fedora — [name@hostpath]$, где name — ваше имя пользователя, host — имя вашей машины, а path — текущий рабочий каталог (см. подраздел 2.4.1). Если вы знакомы с системой Windows, окно оболочки будет выглядеть примерно как командная строка DOS, в macOS приложение Terminal, по сути, совпадает с окном оболочки Linux.
Эта книга содержит множество команд, которые вы будете вводить в командной строке. Все они начинаются с одного знака $, который обозначает приглашение оболочки. Например, наберите следующую команду (только часть, которая выделена жирным шрифтом, а не знак $) и нажмите клавишу Enter:
$ echo Hello there.
Примечание
Многие команды оболочки в этой книге начинаются со знака #. Вы должны запускать их от имени суперпользователя (root), поэтому они требуют особой осторожности. Лучше всего при запуске таких команд применять команду sudo, чтобы защитить систему и записать все действия в лог, который вы позже сможете просмотреть на предмет возможных ошибок. О том, как это сделать, говорится в разделе 2.20.
Теперь введите команду
$ cat /etc/passwd
Она отображает содержимое системного файла /etc/passwd, а затем возвращает приглашение оболочки. Пока не обращайте внимания на вывод команды, вы узнаете все об этом в главе 7.
Текст команды обычно начинается с названия программы для запуска и может сопровождаться аргументами (arguments), которые сообщают программе, с чем работать и как именно. В приведенном примере используется программа cat, в нее добавлен один аргумент, /etc/passwd. Многие аргументы являются параметрами (options), которые изменяют поведение программы по умолчанию и обычно начинаются с дефиса (-). Далее это будет показано при описании команды ls. Однако есть исключения, которые не соответствуют этой обычной структуре команд, — встроенные модули оболочки и переменные окружения.
Программа cat одна из самых простых для понимания в системах Unix, она просто выводит содержимое одного или нескольких файлов или другого источника ввода. Синтаксис команды cat выглядит следующим образом:
$ catfile1 file2...
При выполнении cat выводит содержимое файлов file1, file2 и любых других файлов, указанных в качестве аргументов (в примере это обозначено многоточием ...), а затем завершает работу. Программа называется cat, потому что она выполняет конкатенацию (concatenation, присоединение), когда выводит содержимое нескольких файлов. Существует много способов запустить cat. Изучим процесс ввода-вывода Unix с помощью этой программы.
Процессы Unix используют потоки ввода-вывода (Input/Output, I/O streams) для чтения и записи данных. Они считывают данные из входных потоков и записывают данные в выходные потоки. Сами по себе потоки очень гибкие. Например, источником потока ввода могут быть файл, устройство, окно терминала или даже выходной поток из другого процесса.
Чтобы увидеть поток ввода в работе, введите команду cat (без аргументов) и нажмите клавишу Enter. На этот раз вывод появится не сразу, и вы не получите приглашение оболочки, потому что cat все еще работает. Теперь введите что-нибудь и нажмите клавишу Enter в конце каждой строки. Теперь команда cat повторяет любую строку, которую вы вводите. Как только вам это наскучит, нажмите сочетание клавиш Ctrl+D в пустой строке, чтобы завершить команду cat и вернуться к командной строке.
Причина, по которой команда cat так сработала, связана с потоками. Если вы не указываете входное имя файла, cat считывает данные из стандартного потока ввода (standard input), предоставляемого ядром Linux, а не из потока, подключенного к файлу. В этом случае стандартный поток ввода подключен к терминалу, где вы запускаете команду cat.
Примечание
Нажатие сочетания клавиш Ctrl+D на пустой строке останавливает текущую стандартную запись ввода с терминала с сообщением EOF (end-of-file, конец файла) и в большинстве случаев завершит и саму программу. Не путайте с сочетанием клавиш Ctrl+C, которое обычно завершает программу независимо от ее ввода или вывода.
Стандартный потоквывода (standard output) работает точно так же. Ядро предоставляет каждому процессу стандартный поток вывода, в который процессы могут записывать свои выходные данные. Команда cat всегда записывает свои выходные данные в стандартный поток вывода. При запуске cat в терминале в приведенных ранее примерах стандартный вывод был подключен к этому терминалу, так что именно там отображался вывод.
Стандартный ввод и вывод часто сокращают как stdin и stdout соответственно. Многие команды работают так же, как команда cat: если вы не указываете входной файл, команда читает из stdin. Вывод же немного отличается. Некоторые программы (например, cat) отправляют выходные данные только в stdout, но другие имеют возможность отправлять выходные данные непосредственно в файлы.
Существует и третий стандартный поток ввода-вывода, называемый стандартной ошибкой (standard error). О нем рассказывается в подразделе 2.14.1.
Одна из самых полезных особенностей стандартных потоков заключается в том, что вы можете легко управлять ими для чтения и записи не только в терминале (см. раздел 2.14). В частности, вы узнаете, как подключать потоки к файлам и другим процессам.
Теперь рассмотрим еще несколько команд Unix. Большинство из приводимых здесь программ работают только с несколькими аргументами, а некоторые имеют так много параметров и форматов, что их сокращенный список был бы бессмысленным. Далее представлен упрощенный список основных команд — вам пока не нужны все детали.
Команда ls перечисляет (lists) содержимое каталога. По умолчанию используется текущий каталог, но вы можете добавить любой каталог или файл в качестве аргумента, и для этой операции существует много полезных параметров. Например, применяйте ls-l для подробного (long, длинного) списка и ls-F для отображения информации о типе файла. Вот пример длинного списка, он включает владельца файла (столбец 3), группу (столбец 4), размер файла (столбец 5) и дату/время изменения (между столбцом 5 и именем файла):
$ ls -l
total 3616
-rw-r--r-- 1 juser users 3804 May 28 10:40 abusive.c
-rw-r--r-- 1 juser users 4165 Aug 13 10:01 battery.zip
-rw-r--r-- 1 juser users 131219 Aug 13 10:33 beav_1.40-13.tar.gz
-rw-r--r-- 1 juser users 6255 May 20 14:34 country.c
drwxr-xr-x 2 juser users 4096 Jul 17 20:00 cs335
-rwxr-xr-x 1 juser users 7108 Jun 16 13:05 dhry
-rw-r--r-- 1 juser users 11309 Aug 13 10:26 dhry.c
-rw-r--r-- 1 juser users 56 Jul 9 15:30 doit
drwxr-xr-x 6 juser users 4096 Feb 20 13:51 dw
drwxr-xr-x 3 juser users 4096 Jul 1 16:05 hough-stuff
Подробнее о столбце 1 этого вывода рассказывается в разделе 2.17. Вы можете пока игнорировать столбец 2 — это количество жестких ссылок на файл, о нем говорится в разделе 4.6.
В своей простейшей форме команда cp копирует файлы. Например, чтобы скопировать файл file1 в file2, введите следующее:
$ cpfile1 file2
Вы также можете скопировать файл в другой каталог, сохранив в нем то же имя файла:
$ cpfile dir
Чтобы скопировать более одного файла в каталог (папку) с именем dir, попробуйте применить команду из следующего примера, которая копирует три файла:
$ cpfile1 file2 file3 dir
Команда mv (move) работает так же, как и команда cp. В своей простейшей форме она переименовывает файл. Например, чтобы переименовать файл file1 в file2, введите следующее:
$ mvfile1 file2
Можно использовать команду mv для перемещения файлов в другие каталоги таким же образом, что и команду cp.
Команда touch может создать файл. Если целевой файл уже существует, touch не изменяет его, но обновляет временную метку (timestamp) его изменения. Например, чтобы создать пустой файл, введите следующее:
$ touchfile
Затем запустите в нем команду ls-l. Появится вывод, как в следующем примере, где дата и время указывают, когда была запущена команда touch:
$ ls -lfile
-rw-r--r-- 1 juser users 0 May 21 18:32 file
Чтобы увидеть обновление метки времени, подождите не менее минуты, а затем снова выполните ту же команду touch. Метка времени, возвращенная из команды ls-l, будет обновлена.
Команда rm удаляет (removes) файл. После этого он обычно исчезает из вашей системы и, как правило, не может быть восстановлен, если вы не создали его резервную копию:
$ rmfile
Команда echo выводит свои аргументы в стандартный вывод:
$ echo Hello again.
Hello again.
Команда echo очень полезна для шаблонов поиска и подстановки имен файлов оболочки (подстановочных знаков (wildcards), таких как *) и переменных (таких, как $HOME), о которых вы узнаете позже в этой главе.
Иерархия каталогов Unix начинается с каталога /, называемого также корневым (root directory). Разделителем каталогов является косая черта (/), но не обратная косая черта (\). В корневом каталоге есть несколько стандартных подкаталогов, таких как /usr, о которых вы узнаете из раздела 2.19.
Ссылаясь на файл или каталог, вы указываете путь (path) или имя пути (pathname). Путь, начинающийся со знака / (например, /usr/lib), — это полный, или абсолютный путь.
Компонент пути, обозначенный двумя точками (..), указывает на то, что это родительский каталог. Например, если вы работаете в каталоге /usr/lib, путь .. ведет к /usr. Аналогично ../bin ведет к /usr/bin.
Одна точка (.) относится к текущему каталогу. Например, если вы находитесь в каталоге /usr/lib, путь . по-прежнему ведет к /usr/lib, а путь ./X11 — к каталогу /usr/lib/X11. Нет нужды применять одну точку . очень часто, потому что большинство команд по умолчанию задействуют текущий каталог, если путь не начинается со знака / (поэтому вместо ./X11 можно использовать X11).
Путь, не начинающийся с косой черты /, называется относительным. Большую часть времени вы будете работать с относительными путями, потому что уже находитесь в нужном каталоге или рядом с ним. Теперь, когда у вас есть представление об основных механизмах работы с каталогами, перечислим некоторые основные команды каталогов.
Текущий рабочий каталог (current working directory) — это каталог, в котором в данный момент находится процесс (например, командная оболочка). В дополнение к командной строке по умолчанию в большинстве дистрибутивов Linux вы можете просмотреть текущий каталог с помощью команды pwd, описанной в подразделе 2.5.3.
Каждый процесс может самостоятельно установить собственный текущий рабочий каталог. Команда cd изменяет текущий рабочий каталог оболочки:
$ cddir
Если вы опустите dir, оболочка вернется в ваш домашний каталог (home directory) — первоначальный каталог входа в систему. Некоторые программы обозначают домашний каталог символом ~ (волнистая черта, тильда).
Примечание
Команда cd встроена в командную оболочку. Она не работает как отдельная программа, потому что, если бы она запускалась как подпроцесс, то не смогла бы (чаще всего) изменить текущий родительский рабочий каталог. В данный момент это может показаться не особо важным отличием, однако бывают моменты, когда этот факт может прояснить путаницу.
Команда mkdir создает новый каталог dir:
$ mkdir dir
Команда rmdir удаляет каталог dir:
$ rmdir dir
Если в каталоге dir есть данные, эта команда не завершается и выводит ошибку. Однако вы можете не захотеть сначала тщательно удалить все файлы и подкаталоги внутри dir. Удаляйте каталог и его содержимое с помощью команды rm-rdir, но будьте осторожны! Это одна из немногих команд, которая способна нанести серьезный ущерб, особенно если вы запускаете ее от имени суперпользователя. Параметр -r указывает на рекурсивное удаление (recursive delete), убирающее все внутри dir. Не применяйте флаг -r с шаблонами поиска, такими как знак звездочки (*). И, конечно же, всегда перепроверяйте команду, прежде чем запускать ее.
Оболочка может сопоставлять простые шаблоны с именами файлов и каталогов, этот процесс известен как подстановка имен файлов (globbing). Это похоже на концепцию подстановочных знаков в других системах. Самым простым из них является символ *, обозначающий любое количество произвольных символов. Например, следующая команда выводит список файлов, находящихся в текущем каталоге:
$ echo *
Оболочка сопоставляет шаблоны с именами файлов, подставляет имена файлов в соответствии с аргументами, а затем запускает модифицированную команду. Подстановка называется расширением шаблона, потому что оболочка подставляет все совпадающие имена файлов под упрощенное выражение. Вот несколько способов использования символа * для расширения имен файлов.
• Команда at* расширяет вывод до всех имен файлов, которые начинаются с at.
• Команда *at расширяет вывод до всех имен файлов, которые заканчиваются на at.
• Команда *at* расширяет вывод до всех имен файлов, которые содержат at.
Если ни один файл не соответствует шаблону, оболочка bash не производит расширение и команда выполняется как написано буквально, без подстановки специальных символов, таких как *. Например, попробуйте выполнить команду echo*dfkdsafh.
Примечание
Если вы привыкли к командной строке Windows, то можете машинально ввести *.*, чтобы обратиться ко всем файлам. Откажитесь от этой привычки. В Linux и других версиях Unix используется * как символ соответствия всем файлам. В оболочке Unix *.* соответствует только файлам и каталогам, в именах которых есть символ точки (.). Имена файлов Unix не нуждаются в расширениях и часто не имеют их.
Другой символ шаблона поиска — знак вопроса (?) — указывает на соответствие ровно одному произвольному символу. Например, b?at соответствует boat и brat.
Если вы не хотите, чтобы оболочка расширяла шаблон в команде, заключите его в одинарные кавычки ('). Например, команда echo'*' выводит звездочку. Это удобно для выполнения некоторых команд, описанных в следующем разделе, таких как grep и find. (Вы узнаете больше о заключении в кавычки в разделе 11.2.)
Примечание
Важно помнить, что оболочка выполняет расширения перед выполнением команд. Поэтому, если символ * превращается в команду без расширения, оболочка больше ничего с ней не сделает: дальнейшие интерпретации зависят от самой команды.
Конечно, это еще не все возможности шаблонов оболочки, однако пока достаточно изучить символы * и ?. В разделе 2.7 описывается, как ведут себя шаблоны с теми забавными файлами, которые начинаются с точки.
В этом разделе описаны наиболее важные команды Unix среднего уровня.
Команда grep выводит строки из файла или потока ввода, соответствующие выражению. Например, чтобы напечатать строки из файла /etc/passwd, содержащие текст root, введите следующее:
$ grep root /etc/passwd
Команда grep чрезвычайно удобна, когда нужно работать с несколькими файлами одновременно, поскольку она печатает имя файла в дополнение к найденной строке. Например, если вы хотите проверить каждый файл в /etc, содержащий слово root, используйте команду
$ grep root /etc/*
Два наиболее важных параметра grep — это -i (для поиска без учета регистра) и -v (инвертированный поиск, вывод всех строк, которые не подпадают под выражение). Существует также более мощный вариант команды под названием egrep (является просто синонимом grep-E).
Команда grep понимает регулярные выражения (regular expressions, regexp), шаблоны, которые основаны на теории информатики и очень распространены в утилитах Unix. Регулярные выражения более мощны, чем шаблоны в стиле подстановочных знаков, и у них другой синтаксис. Есть три важные вещи, которые следует помнить о регулярных выражениях:
• .* соответствует любому количеству символов, в том числе ни одному (например, * в шаблонах и подстановочных знаках);
• .+ соответствует любому одному или нескольким символам;
• . соответствует ровно одному произвольному символу.
Примечание
Страница руководства grep(1) содержит подробное описание регулярных выражений, но его довольно трудно читать. Чтобы узнать больше, вы можете прочитать третье издание книги Джеффри Э.Ф. Фридла «Регулярные выражения» (Символ-плюс, 2008) или просмотреть главу о регулярных выражениях в книге Тома Кристенсена и др. «Программирование на Perl» (Символ-плюс, 2014). Если вы любите математику и интересуетесь, откуда берутся регулярные выражения, изучите книгу Джеффри Уллмана и Джона Хопкрофта «Введение в теорию автоматов, языков и вычислений» (Диалектика, 2019).
Команда less используется, когда файл довольно большой или вывод команды длинный и не помещается на экране.
Чтобы просмотреть большой файл, например /usr/share/dict/words, можете применить команду less/usr/share/dict/words. Содержимое файла будет отображаться фрагментами по размеру окна терминала. Нажмите Пробел, чтобы перейти вперед по тексту файла, нажатие клавиши b (в нижнем регистре) поможет вернуться назад. Чтобы выйти, нажмите клавишу q.
Примечание
Команда less — это расширенная версия старой программы more. Настольные компьютеры и серверы Linux используют команду less, но она не применяется по умолчанию для многих встроенных систем и других систем Unix. Если вы когда-нибудь столкнетесь с ситуацией, когда не сможете задействовать команду less, берите команду more.
Вы также можете искать текст внутри вывода команды less. Например, для поиска слова вперед по тексту можно ввести /word, а для поиска назад — -?ord. Когда будет найдено совпадение, нажмите клавишу n, чтобы продолжить поиск.
Как описано в разделе 2.14, вы можете отправить стандартный вывод практически любой программы непосредственно на стандартный ввод другой программы. Это полезно, когда у вас есть команда с большим количеством выходных данных и вы хотели бы использовать команду less для их просмотра. Вот пример отправки выходных данных команды grep в less:
$ grep ie /usr/share/dict/words | less
Попробуйте сделать это. Вероятно, вы найдете много подобных применений для команды less.
Команда pwd (print working directory, вывод рабочего каталога) просто выводит имя текущего рабочего каталога. Вы можете задаться вопросом, зачем она нужна, если большинство дистрибутивов Linux настраивают учетные записи пользователей с текущим рабочим каталогом в приглашении командной строки. На это есть две причины.
Во-первых, не все приглашения включают текущий рабочий каталог, особенно если в дальнейшем от него нужно избавиться, потому что он занимает много места. Для этого вам понадобится команда pwd.
Во-вторых, символические ссылки, о которых вы узнаете в разделе 2.17.2, иногда могут скрывать истинный полный путь к текущему рабочему каталогу. Используйте команду pwd-P, чтобы устранить эту путаницу.
Чтобы увидеть различия (difference) между двумя текстовыми файлами, задействуйте команду diff:
$ difffile1 file2
Несколько параметров могут управлять форматом вывода, и он по умолчанию наиболее понятен для пользователя. Однако большинство программистов предпочитают вывод из команды diff-u, когда им нужно перенаправить этот вывод куда-то еще, потому что автоматизированным инструментам легче работать с таким форматом.
Если вы видите файл и не уверены в его формате, попробуйте команду file, чтобы узнать, сможет ли система распознать его:
$ filefile
Удивительно, как много может сделать эта на первый взгляд незначительная команда.
Обидно, когда вы знаете, что определенный файл точно существует в каком-то из каталогов, но не знаете, где именно. Чтобы найти файл, запустите команду find с указанием каталога dir, как в следующем примере:
$ finddir-namefile-print
Как и большинство программ, описанных в этом разделе, команда find способна еще на некоторые необычные вещи. Однако не используйте такие параметры, как -exec, пока не выучите наизусть форму, показанную здесь, и не поймете, зачем нужны параметры -name и -print. Команда find принимает специальные символы, шаблоны, такие как *, но их нужно заключить в одинарные кавычки ('*'), чтобы не дать специальным символам выполниться непосредственно в оболочке. (Как говорилось в подразделе 2.4.4, оболочка расширяет шаблоны перед выполнением команд.)
В большинстве систем для поиска файлов используется также команда locate. Вместо того чтобы искать файл в режиме реального времени, locate выполняет поиск по индексу, который периодически создается системой. Поиск с помощью команды locate намного быстрее, чем с командой find, но если нужный файл новее созданного индекса, locate не найдет его.
Команды head и tail позволяют быстро просматривать часть файла или потока данных. Например, команда head/etc/passwd показывает первые 10 строк файла с паролями, а tail/etc/passwd — последние 10 строк.
Чтобы изменить количество отображаемых строк, используйте параметр -n, где n — это количество строк (например, head-5/etc/passwd). Для вывода строк, начинающихся со строки n, используйте tail+n.
Команда sort сортирует строки текстового файла в алфавитно-цифровом порядке. Если строки файла начинаются с цифр и вы хотите отсортировать их в числовом порядке, используйте параметр -n. Параметр -r изменяет порядок сортировки на обратный.
Используйте команду passwd для изменения пароля. Система попросит ввести старый пароль, а затем дважды ввести новый.
Лучше всего создавать длинные пароли, которые представляют собой бессмысленные предложения, но которые легко запомнить. Чем длиннее пароль (с точки зрения числа символов), тем лучше; попробуйте использовать 16 символов или более. (Раньше количество символов было ограничено, поэтому система советовала добавлять необычные символы и т.п.)
Вы можете изменить свою оболочку с помощью команды chsh (на альтернативу, такую как zsh, ksh или tcsh), но имейте в виду, что в этой книге применяется оболочка bash, поэтому, если вы смените оболочку, некоторые примеры могут не сработать.
Перейдите в свой домашний каталог, введите команду ls, чтобы осмотреться, а затем запустите команду ls-a. Видите ли вы разницу в результатах? При запуске команды ls без параметра -a файлы конфигурации, называемые файлами с точками (дот-файлами, скрытыми файлами), не отображаются. Это файлы и каталоги, имена которых начинаются с точки (.). Обычные файлы с точками — это .bashrc и .login, а также каталоги с точками, такие как .ssh.
В файлах и каталогах с точками нет ничего особенного. Некоторые программы не показывают их по умолчанию, так что полного беспорядка при перечислении содержимого вашего домашнего каталога не будет. Например, команда ls не перечисляет файлы с точками, если вы не используете параметр -a. Кроме того, шаблоны оболочки не подпадают под файлы с точками, если вы явно не применяете такой шаблон, как .*.
Примечание
Вы можете столкнуться с проблемой с шаблонами, потому что символ .* совпадает с точками . и .. (текущий и родительский каталоги). Используйте шаблон .[^.]* или .??*, чтобы вывести все файлы с точками, кроме текущего и родительского каталогов.
Оболочка может хранить временные переменные, называемые переменными оболочки, содержащие значения текстовых строк. Переменные оболочки очень полезны для отслеживания значений в скриптах, а некоторые из них управляют поведением оболочки. (Например, оболочка bash считывает переменную PS1 перед отображением приглашения.)
Чтобы присвоить значение переменной оболочки, используйте знак равенства (). Вот простой пример:
$ STUFF=blah
Здесь значение переменной с именем STUFF устанавливается равным значению blah. Чтобы обратиться к этой переменной, используйте $STUFF (например, попробуйте запустить команду echo$STUFF). Вы узнаете о многих примерах использования переменных оболочки в главе 11.
Примечание
Не ставьте никаких пробелов вокруг знака равенства (=) при присвоении значения переменной.
Переменная окружения похожа на переменную оболочки, но она не специфична для оболочки. Все процессы в системах Unix имеют хранилище переменных окружения. Основное различие между переменными окружения и оболочки заключается в том, что операционная система передает все переменные окружения оболочки программам, выполняемым оболочкой, в то время как переменные оболочки недоступны в запускаемых вами командах.
Переменная окружения назначается с помощью команды export. Например, если вы хотите превратить переменную оболочки $STUFF в переменную окружения, введите следующее:
$ STUFF=blah
$ export STUFF
Поскольку дочерние процессы наследуют переменные окружения от родительских, многие программы считывают их для собственной настройки и получения параметров. Например, вы можете поместить свои любимые параметры командной строки less в переменную окружения LESS, и команда less будет использовать их при запуске. (Во многих руководствах есть раздел «Окружение» (ENVIRONMENT), описывающий эти переменные.)
PATH — это специальная переменная окружения, содержащая путь к команде (или сокращенно путь) — список системных каталогов, где оболочка пытается найти команду. Например, при запуске команды ls оболочка выполняет поиск в каталогах, перечисленных в PATH для команды ls. Если программы с одинаковым именем появляются в нескольких каталогах в пути, оболочка запускает первую из найденных программ.
Если запустить команду echo$PATH, можно увидеть, что компоненты пути разделены двоеточиями (:), например:
$ echo $PATH
/usr/local/bin:/usr/bin:/bin
Чтобы дать оболочке задание искать программы в большем количестве мест, измените переменную окружения PATH. Например, с помощью приведенной далее команды можно добавить в начало пути каталог dir, чтобы оболочка просматривала его перед поиском в любом другом каталоге переменной PATH:
$ PATH=dir:$PATH
Или можете добавить имя каталога в конец переменной PATH, в результате чего оболочка будет просматривать каталог dir последним:
$ PATH=$PATH:dir
Примечание
Вы можете случайно стереть весь свой путь, если неправильно наберете $PATH при его изменении. Если это произошло, не паникуйте! Это не навсегда — можно просто запустить новую оболочку. (Для длительного эффекта вам нужно ввести путь неправильно при редактировании определенного файла конфигурации, но даже это нетрудно исправить.) Самый простой способ вернуться к нормальному состоянию оболочки — закрыть текущее окно терминала и запустить другое.
При обсуждении Linux необходимо знать названия нескольких специальных символов, с которыми вы столкнетесь во время работы. Если вас забавляют подобные вещи, изучите словарь для хакеров Jargon File (www.catb.org/jargon/html/) или его печатную версию — книгу Эрика С. Рэймонда New Hacker’s Dictionary (MIT Press, 1996).
В табл. 2.1 приведены избранные специальные символы, многие из которых вы уже встречали в этой главе. Некоторые утилиты, такие как язык программирования Perl, используют почти все эти специальные символы! (В скобках приведены американские названия специальных символов.)
Примечание
Вы часто будете встречать управляющие символы, отмеченные знаком карет, например, ^C для Ctrl+C.
Таблица 2.1. Специальные символы
Символ
Название
Значение
*
Звездочка, или астериск (star, asterisk)
Регулярное выражение, символ шаблона
.
Точка (dot)
Текущий каталог, разделитель имени файла/хоста
!
Восклицательный знак (bang)
Отрицание, история команд
|
Вертикальная черта (pipe)
Конвейер (канал) для команд
/
Косая черта (slash)
Разделитель каталогов, команда поиска
\
Обратная косая черта, (backslash)
Литералы, макросы (но НЕ каталоги)
$
Доллар (dollar)
Переменные, конец строки
'
Одинарные кавычки (tick, quote)
Не интерпретируемые как шаблоны литеральные строки
`
Обратный апостроф (backtick, backquote)
Подстановка команд
"
Двойные кавычки (double quote)
Частично интерпретируемые как шаблоны (полулитеральные) строки
^
Карет (caret)
Отрицание, начало строки
~
Тильда, волнистая линия (tilda, squiggle)
Отрицание, ярлык каталога
#
Октоторп, решетка, хеш, фунт, шарп (hash, sharp, pound)
Комментарии, препроцессор, подстановка
[ ]
Квадратные скобки (square brackets)
Диапазоны
{ }
Фигурные скобки (curly brackets, braces)
Блоки выражений, диапазоны
_
Нижнее подчеркивание (underscore, under)
Заменитель пробела, когда пробелы не нужны или не разрешены либо когда запутываются алгоритмы автозаполнения
Практикуясь в работе с командной оболочкой, обратите внимание на то, что вы можете редактировать команды прямо в командной строке с помощью клавиш со стрелками влево и вправо, а также просматривать предыдущие команды с помощью стрелок вверх и вниз. Это стандарт большинства систем Linux.
Однако лучше забыть о клавишах со стрелками и вместо этого использовать сочетания клавиш управления (control key). Если вы изучите перечисленные в табл. 2.2 сочетания, то обнаружите, что во многих программах Unix с их помощью вводить текст гораздо удобнее, чем с использованием клавиш со стрелками.
Таблица 2.2. Сочетания клавиш командной строки
Сочетание клавиш
Действие
Ctrl+B
Переместить курсор влево
Ctrl+F
Переместить курсор вправо
Ctrl+P
Переместить курсор выше (просмотреть предыдущую команду)
Ctrl+N
Переместить курсор ниже (просмотреть следующую команду)
Ctrl+A
Переместить курсор в начало строки
Ctrl+E
Переместить курсор в конец строки
Ctrl+W
Стереть предыдущее слово
Ctrl+U
Стереть все от курсора до начала строки
Ctrl+K
Стереть все от курсора до конца строки
Ctrl+Y
Вставить стертый текст (например, после использования Ctrl+U)
Поскольку мы перешли к теме редактирования, пришло время изучить текстовые редакторы. Чтобы серьезно работать в системах Unix, необходимо уметь редактировать текстовые файлы, не повреждая их. Большинство частей системы используют обычные текстовые файлы конфигурации (например, файл /etc). Редактировать файлы несложно, но вы будете делать это так часто, что вам точно понадобится мощный инструмент для этой работы.
Необходимо изучить один из двух стандартных текстовых редакторов Unix: vi или Emacs. Большинство пользователей Unix непреклонны в своем выборе редактора, но не слушайте их. Просто выбирайте сами. Если выберете тот, который соответствует вашему стилю работы, вам будет легче научиться. В принципе, выбор сводится к следующему.
• Если вам нужен редактор, который может делать практически все, имеет обширное онлайн-руководство и вы не возражаете против дополнительного ввода текста, чтобы использовать эти функции, попробуйте редактор Emacs.
• Если скорость — это самое важное, попробуйте редактор vi, его действия и возможности похожи на видеоигру.
Книга Арнольда Роббинса, Элберта Ханна и Линды Ламб Learning the vi and Vim Editors: Unix Text Processing