UNIX

(перенаправлено с «Unix»)

О чём эта книга

править

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

Подробное рассмотрение команд и их флагов, системных вызовов, файлов также выходит за рамки данной книги. Любую команду или системный вызов можно посмотреть командой man, а если нет под рукой UNIX - то на сайте opennet.ru. Флаги и параметры самой команды man можно посмотреть командой

man man

Кроме того, полезны команды apropos (она же man -k) и whatis.

В конце 1970-х UNIX разделился на две версии: System V и BSD. Между этими версиями есть некоторые различия, и они будут отмечаться в тексте.

Файловая система

править
Пример работы с файлами.

Основные понятия

править

В первом приближении файловая система в UNIX древовидная. Корневой каталог обозначается символом / (слеш) и содержит обычные файлы (regular files) и каталоги (directories) первого уровня, которые содержат обычные файлы и каталоги второго уровня, которые содержат обычные файлы и каталоги третьего уровня, и так далее - до какой угодно глубины. Сейчас древовидная файловая система стала стандартом (во многом именно благодаря использованию её в UNIX), но в 1971 году, когда была выпущена первая версия UNIX, она была новым, нетривиальным и мудрым решением.

«Обычные файлы» и «каталоги» обозначаются общим названием «файлы». Кроме того, существуют и другие типы файлов (файлы устройств, сокеты, FIFO, символические ссылки), которые также хранятся в каталогах. Подробнее о них будет сказано ниже.

У каждого файла есть имя. В UNIX, в отличие от MS Windows, например, имя чувствительно к регистру: Vasya и vasya - разные имена. Имя может состоять из любых символов, кроме слеша (/). Но многие программы, в том числе командные оболочки, придают многим символам специальный смысл. Поэтому лучше всего во избежание проблем использовать только маленькие и заглавные буквы, цифры, подчерк, точку, плюс и минус (ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.+_-) и не начинать имя с плюса или минуса. По соглашению, часть имени обычного файла после точки имеет специальный смысл и обозначает тип файла. Некоторые типы, характерные именно для UNIX или очень распростанённые:

  • .txt - текстовый файл
  • .man - документация системы man
  • .c - программа на языке Си
  • .gz, .Z - сжатый файл (.gz - программой gzip, .Z - программой compress)
  • .tar - архив, созданный системой tar

И много, много других - как, собственно, и в Windows. Но в Unix, в отличие от MS Windows, часто используются 2 префикса или даже больше. Например, если сжать программу на языке Си, её имя будет кончаться на .c.gz

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

Полное, или абсолютное, имя файла рекурсивно определяется как полное имя каталога, в котором он содержится, за которым следует слеш и имя файла. Полное имя корневого каталога - /. Так, в корневом каталоге / может содержаться каталог home (полное имя /home), в котором содержится каталог vasya (полное имя /home/vasya), в котором может содержаться каталог fotki (полное имя /home/vasya/fotki), в котором может содержаться файл masha.jpg (полное имя /home/vasya/fotki/masha.jpg).

В каждый данный момент каждый пользователь и каждый процесс (о процессах см. ниже) находится в каком-то текущем каталоге. Относительное имя файла определяет его путь из текущего, а не корневого каталога, и не начинается со слеша. Так, если пользователь vasya сейчас находится в каталоге /home/vasya, то файл /home/vasya/fotki/masha.jpg имеет относительное имя fotki/masha.jpg. К файлам можно обращаться как по абсолютным, так и по относительным именам.

К именам каталогов (абсолютным и относительным) можно в конце добавлять слеш. В большинстве случаев он ни на что не влияет.

Во втором приближении, каталоги содержат не сами файлы (и каталоги), а имена файлов (и каталогов) и ссылки на них. Благодаря этому один и тот же файл (но не каталог) может содержаться под разными именами в разных каталогах (или под одним и тем же именем в разных каталогах, или под разными именами - в одном и том же). Создание новой ссылки на файл (но не каталог) осуществляется командой ln, например

ln kartinki/masha.jpg devushki/masha.jpg

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

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

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

Наконец, совсем строго говоря, каталог содержит ссылки не на файлы, а на индексные дескрипторы файлов. Индексный дескриптор, он же inode (произносится ай-нод, с ударением на о), содержит всю известную системе информацию о файлах, в частности время создания, время последнего изменения, длину, ссылку на сам файл, кто владеет этим файлом (имена пользователя и группы), права доступа (см. ниже), что это за файл (обычный файл, каталог и т.д.), а также - и это необходимо - количество ссылок на этот индексный дескриптор (если это конечно не каталог). При создании новой ссылки командой ln, количество ссылок увеличивается на 1, при стирании - уменьшается на 1. Если количество ссылок становится равно 0, вызывается системный вызов unlink(), удаляющий упоминание о файле из каталога и помечающий место, занимаемое этим файлом, как свободное. После этого оно может быть использованно для хранения других файлов, однако до фактической перезаписи сохраняется [теоретическая] возможность восстановления, на практике же возможность восстановления зависит от типа используемой файловой системы.

Важно понимать, что индексный дескриптор не знает, откуда на него ссылаются. Поэтому в UNIX, имея файл, невозможно определить, в каких ещё каталогах есть ссылки на него. (То есть можно, но лишь просмотрев все файлы ФС.)

Распространённые каталоги

править

В типичной файловой системе есть следующие каталоги и файлы. (На самом деле файловое дерево современных UNIX-ов гораздо глубже и сложнее; здесь приводятся только самые важные и распространённые файлы и директории.)

  • /bin - наиболее важные команды общего пользования
  • /dev - специальные файлы устройств
  • /etc - системные файлы и команды, в частности:
    • /etc/default - параметры команд по умолчанию (типично для BSD)
    • /etc/rc0.d, /etc/rc1.d, /etc/rc2.d и т. д. - скрипты инициализации системы (могут отсутствовать в BSD)
    • /etc/rc0, /etc/rc1, /etc/rc2 и т. д. - скрипты, которые управляют скриптами инициализации системы (могут отсутствовать в BSD)
    • /etc/rc.boot, /etc/rc, /etc/rc.local - скрипты инициализации системы в BSD
  • /home - каталог, содержащий пользовательские каталоги. У каждого пользователя есть свой личный каталог. Каталог пользователя vasya обычно называется /home/vasya. Иногда этот каталог называется не /home, а /u, а в старых версиях UNIX - /usr. В своём личном каталоге многие пользователи создают свои каталоги и деревья каталогов.
  • /lib - библиотечные файлы
  • /lost+found - файлы, которые из-за сбоя файловой системы стали «сиротами»: индексный дескриптор цел, но файла нет ни в одном каталоге. Получается, что система не знает имени файла и где он находился. Программы починки файловой системы помещает эти файлы сюда.
  • /mnt - каталог для привязывания (монтирования) физических файловых систем к корневой, о чём подробнее ниже. Если в компьютере больше одного диска, все диски, кроме главного, являются подкаталогами в этом каталоге.
  • /sbin - исполняемые системные файлы (System V). В других UNIX эти файлы находятся в /etc. В некоторых версиях System V они находятся не только в /sbin, но и в /usr/sbin.
  • /tmp - временные файлы. Обычно все имеют право создавать файлы в этом каталоге.
  • /usr - дополнительные команды, библиотеки и другие нужные пользователям файлы.
    • /usr/bin - команды общего пользования. Иногда с этой директории делается твёрдая или символическая ссылка на /bin. То же самое бывает верно и для других подкаталогов каталога /usr.
    • /usr/lib - библиотеки
    • /usr/include - заголовочные файлы
    • /usr/sbin - системные файлы
    • /usr/local - файлы, локальные для данного компьютера
    • /usr/man (/usr/share/man) - инструкции к командам, файлам, функциям - выдаются командой man.
    • /usr/spool - каталоги сервисных подсистем (печати, электронной почты и т. д.)
    • /var - заменяет /usr/spool в System V.

Основные команды

править

Основные команды для работы с файлами и каталогами:

  • ls - вывод списка файлов, по умолчанию текущего каталога. У этой команды есть множество флагов и параметров, в частности
    • ls -l - длинный формат (один файл на строку, выводится подробная информация о каждом)
    • ls -a - вывод в том числе файлов, имя которых начинается с точки (.) По умолчанию они не выводятся
    • ls -F - к имени файла добавляется символ, соответствующий его типу: / для директории, * для выполняемых файлов (о выполняемых файлах см. ниже) и т. д.
    • ls -R - рекурсивный вывод подкаталогов
    • ls [файл] ... [файл] - вывод этих файлов. Если файл - обычный файл, выводится информация о нём, а если каталог - список его файлов. Если списка файлов нет, выводится список файлов текущего каталога.
    • Флаги могут комбинироваться, например ls -Fla (возможность комбинировать флаги стандартна для команд UNIX).
    • Часть имени файла может заменяться звёздочками, например ls x*выведет все файлы, имя которых начинается на x, а ls *.c - все файлы, чьё имя кончается на .c . Эта возможность вообще не является свойством команды ls, a связана с командной оболочкой, о которой см. ниже. Поэтому замена звёздочкой части имени файла возможна в любых командах. Есть и другие подобные возможности.
  • touch [файл] ... [файл] - создать пустые файлы, а если они уже созданы - обновить время последней записи.
  • rm [файл] ... [файл] - стереть файлы. Флаг -r рекурсивно стирает каталоги. Если этого флага нет, файлы не могут быть каталогами.
  • rmdir [каталог] ... [каталог] - стереть пустые каталоги. Непустые каталоги стереть этой командой не получится.
  • mkdir [каталог] ... [каталог] - создать пустые каталоги.
  • cat [файл] ... [файл] - вывод содержимого файлов.
  • mv файл файл - переименовать файл. Можно таким образом передвинуть его в другой каталог.
    • mv [файл] ... [файл] каталог - передвинуть много файлов в каталог.
  • cp файл файл - копировать файл.
    • cp [файл] ... [файл] каталог - копировать много файлов в другой каталог.
  • ln файл файл - создать новую ссылку на файл.
  • cd каталог - поменять текущий каталог
  • pwd - вывести имя текущего каталога

Символические ссылки

править

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

Длина символической ссылки равна длине имени файла. Команда ls в длинном формате пишет имя, на которое символическая ссылка ссылается.

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

Создаются символические ссылки командой

ln -s файл файл

Владельцы и права доступа

править

UNIX изначально спланирован как многопользовательская система (между прочим, в 1971 году не было персональных компьютеров). В UNIX есть пользователи, которые объединены в группы. Каждый пользователь принадлежит одной или нескольким группам. Если он принадлежит к нескольким группам, то одна из них - первичная (primary), остальные - дополнительные (supplementary). Некоторые пользователи — привилегированные, они называются суперпользователями (superuser) и могут делать всё что угодно. Посмотреть своё имя пользователя можно командой whoami. Подробнее см. ниже в разделе «Пользователи и группы».

Каждый файл принадлежит какому–то пользователю и какой–то группе. Изначально владельцем файла становится тот, кто его создал. В System V файл принадлежит группе того, кто его создал, а в BSD - той же группе, что каталог, где он был создан. [1]

Три права и три категории пользователей

править

Для каждого файла существуют следующие категории пользователей

  • u (user) — владелец файла
  • g (group) — члены группы, владеющей файлом
  • о (others) — все прочие

Каждая категория может иметь или не иметь каждое из следующих прав:

  • r (read) — право на чтение
  • w (write) — право на запись
  • x (execute) — право на исполнение

Эти права, таким образом, представляют собой 9 бит, расположенных в порядке rwxrwxrwx. Первые три бита - права владельца, следующие три - права группы, последние 3 - права прочих. Эту 9-битную маску часто записывают в восьмеричной системе счисления.

Три варианта записи прав пользователя
двоичная восьмеричная символьная права на файл права на каталог
000 0 --- нет нет
001 1 --x выполнение чтение файлов и их свойств
010 2 -w- запись нет
011 3 -wx запись и выполнение всё, кроме чтения списка файлов
100 4 r-- чтение чтение имён файлов
101 5 r-x чтение и выполнение доступ на чтение
110 6 rw- чтение и запись чтение имён файлов
111 7 rwx все права все права

Некоторые распространённые маски:

  • 644 - все могут читать, а владелец - ещё и писать (обычный несекретный файл)
  • 755 - все могут читать и исполнять, а владелец - ещё и писать (обычный несекретный исполняемый файл)
  • 600 - владелец может читать и писать, остальные ничего не могут (личный файл)
  • 700 - владелец может всё, остальные ничего (личный исполняемый файл)
  • 400 - владелец может читать, остальные не могут ничего (важный секретный файл)
  • 444 - только для чтения (важный системный файл, например стандартная библиотека)
  • 555 - только для чтения и выполнения (важный системный исполняемый файл)

Изменить маску может только владелец файла или суперпользователь, а делается это командой chmod. Выглядит это так:

  • chmod [ugoa]{+-=}[rwx] файл ... файл

Здесь [ugo] - любая непустая комбинация из букв u,g,o,a (a означает all, то есть все), {+-=} - один из символов + (добавить права), - (отнять права), = (установить права), [rwx] - любая комбинация из символов r,w,x. Например,

  • chmod a-r vasya.txt - всем запретить чтение файла vasya.txt
  • chmod ug+rwx foo bar - владельцу и группе разрешить делать что угодно с файлами foo и bar
  • chmod gо=r knizhka - группе и прочим разрешить читать, и только читать, файл knizhka

Другой способ вызова этой команды - это

  • chmod маска файл ... файл

Посмотреть маску можно командой ls -l.

Изменить владельца или группу можно командами

  • chown владелец файл ... файл
  • chgrp группа файл ... файл

В BSD это имеет право выполнять только суперпользователь, в System V - владелец файла, причём группу он может ставить только свою.

Права доступа к каталогам имеют нетривиальный смысл:

  • право на чтение (r) - право получить имена, и только имена, файлов.
  • право на исполнение (x) - право доступа к индексным дескрипторам, а также право делать каталог текущим (команда cd). Следовательно,
    • для выдачи всей информации о файле в текущем каталоге (команда ls -l, например) это право необходимо и достаточно
    • для любых действий с файлом (чтение, запись, удаление, запуск, получение информации), это право необходимо. Если каталог закрыт для исполнения, его файлы недоступны никак. Можно получить их имена, и всё.
    • для любых операций с файлами не в текущем каталоге нужно право на исполнение во всех промежуточных каталогах на пути к этому файлу, поскольку для того, чтобы идти по пути, нужно обращаться к индексным дескрипторам промежуточных каталогов. То есть, чтобы выполнить ls Foo/Bar/Baz, нужны права на исполнение для каталогов Foo и Foo/Bar и на чтение для каталога Baz.
  • право на запись(w) - право создавать и стирать файлы в каталоге. Права доступа к файлу для его стирания не нужны! Таким образом, право на запись в каталог - очень серьёзное право.

Права r, w и x независимы. Так, если есть право х, но нет права r, то нельзя получить список имён файлов в каталоге, но зная имя файла - можно получить всю информацию о нём.

И, как сказано выше, суперпользователям права не писаны. Система разрешает им любые действия с любыми файлами.

Вышеприведённая 9-битовая схема (три права, три категории пользователей) иногда бывает слишком примитивной. Существуют файлы, которые может изменять/читать/выполнять кто угодно, но не как угодно. Так, например, файл /etc/passwd[2] содержит, помимо прочего, пароли пользователей (в зашифрованном виде). Есть стандартная программа passwd для смены пароля. Необходимо каким-то образом разрешить всем пользователям менять файл /etc/passwd, но не как угодно, а только через программу passwd (иначе они получат возможность поменять чужие пароли и вообще испортить важный системный файл).

Для таких случаев в коде доступа существует бит s. Если запустить исполняемый файл с битом s, он получит те права доступа, которыми обладает его владелец (а не тот, кто его запустил). Стандартная программа passwd умеет менять пароль, принадлежит системе (то есть суперпользователю system), и бит s в ней установлен. Поэтому ей разрешено менять /etc/passwd, кто бы её ни запустил.

Бит s могущественен и опасен. Если пользователь напишет любую программу, установит для неё бит s командой chmod, а затем передаст её суперпользователю командой chown, его программа получит право делать что хочет. Для борьбы с этой опасностью существуют разные методы. В системе BSD передавать файл от пользователя к пользователю или от группы к группе может только суперпользователь. В системе System V передать свой файл другому пользователю может любой, но при этом бит s сбрасывается.

Существует два бита s: для пользователя и для группы. Первый даёт исполняемой программе права её владельца, а второй - права группы-владельца. Бит устанавливается и сбрасывается командой chmod так же, как и другие биты в коде доступа.

chmod [uga]{+-}s файл ... файл

Посмотреть бит s для исполняемых файлов можно командой ls -l. Если он установлен, то, выдавая код доступа, ls заменит x на s.

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

Другие биты

править

Стики-бит (sticky bit, буквально клейкий бит), или бит t, означает, что исполняемый файл сохраняется в памяти и после завершения работы программы, то есть если программа запускается заново, файл не надо повторно читать с диска. В прошлом стики-бит использовался для ускорения работы важных программ. Сейчас, когда диски быстры, а наиболее часто требуемые страницы система всё равно хранит в памяти, стики-бит используется редко.

Бит блокирования, или бит l, означает, что два разных процесса не могут одновременно обращаться к файлу. Так, например, в промежутке между двумя чтениями одним процессом файл не может быть изменён другим процессом. Бит l есть не во всех UNIX.

Биты t и l тоже устанавливаются командой chmod. Бит l может менять суперпользователь или владелец, а бит t - только суперпользователь.

Биты s и t для каталогов

править

Бит t не позволяет пользователю удалять в данном каталоге чужие файлы, если у него нет права на запись в эти файлы. Он нужен, например, для каталога /tmp, где любой может создавать файлы (и, значит, у всех есть право на запись в этот каталог), но не стирать чужие файлы без разрешения.

Бит s для групп означает в System V, что файлы, создаваемые в каталоге, наследуют группу от каталога, а не от создателя. Он позволяет пользователям System V имитировать поведение BSD.

Специальные файлы устройств

править

Спецфайлы, соответствующие физическим или виртуальным устройствам, находятся в каталоге /dev. При вводе-выводе в такой файл вызывается драйвер устройства, который и осуществляет обмен данными с устройством. Имена специальных файлов устройств зависят от реализации. Более или менее стандартные имена:

  • /dev/tty - терминал текущего процесса
  • /dev/cd## - CD-ROM
  • /dev/mouse - мышь
  • /dev/lp## - принтер
  • /dev/mem - физическая память
  • /dev/kmem - виртуальная память ядра (kernel memory)
  • /dev/null - при попытке вывода туда данные исчезают; при попытке ввода - вводится 0 байтов. Это виртуальное устройство полезно, чтобы избавиться от ненужного вывода.
  • /dev/zero - при попытке вывода туда данные исчезают; при попытке ввода - вводятся нули в неограниченном количестве.

Здесь ## обозначает номер устройства.

Спецфайлы создаются командой mknod и системным вызовом mknod.

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

Пользователи и группы

править

Выше уже сказано, что пользователи в UNIX объединены в группы. Каждый пользователь принадлежит одной или нескольким группам. Если он принадлежит к нескольким группам, то одна из них - первичная (primary), остальные - дополнительные (supplementary). Некоторые пользователи — привилегированные, они называются суперпользователями (superuser) и могут делать всё что угодно. Посмотреть своё имя пользователя можно командой whoami, а изменить — командой su.

Информация о пользователях находится в открытом для чтения файле /etc/passwd. Каждый пользователь в этом файле описывается строчкой вида

имя:пароль:UID:GID:информация:каталог:оболочка

Здесь

  • имя - имя пользователя.
  • пароль - пароль в зашифрованном виде, или звёздочка (*) - тогда войти под именем этого пользователя нельзя. Часто для безопасности используются теневые пароли, то есть зашифрованные пароли хранятся не в /etc/passwd, а где-то ещё (обычно в /etc/shadow), причём файл, где они хранятся, закрыт для чтения. В этом случае пароли заменяются буквой x.
  • UID - уникальный номер пользователя. Суперпользователь (см. ниже) имеет UID=0. В Linux номера от 0 до 100 зарезервированны для системных целей.
  • GID - номер (первичной) группы.
  • информация - любая информация о пользователе. В этом поле обычно пишется полное имя пользователя, и часто - его телефон, e-mail и т. д. Иногда это поле называется GECOS, по чисто историческим причинам. GECOS - название древней операционной системы (General Electric Comprehensive Operating System); когда это поле впервые было введено, оно содержало сведения, необходимые для неё.
  • каталог - домашний каталог пользователя
  • оболочка - его командная оболочка. О командных оболочках см. ниже. По умолчанию командной оболочкой является /bin/sh.

В некоторых системах /etc/passwd имеет и другие поля.

Информация о группах хранится в /etc/group. Каждая группа в этом файле описывается строчкой вида

имя:пароль:GID:список членов

Здесь

  • имя - имя группы.
  • пароль - пароль в зашифрованном виде. Если поле пусто, пароль не нужен.
  • GID - номер группы.
  • список членов - список (через запятую) имён пользователей, являющихся членами данной группы, кроме тех, для которых эта группа является первичной.

Суперпользователь имеет номер 0 и (обычно) имя root. Как правило, он может делать всё что угодно. Никакие права доступа для него не писаны. Впрочем, в некоторых реализациях UNIX можно ограничить и права суперпользователя — иногда даже таким образом, что невозможно их восстановить. Последнее предназначено для борьбы с хакерами.

Процессы

править

Процессом в UNIX называется (в первом приближении) выполняющийся исполняемый файл. Если запустить одну и ту же программу несколько раз, получится несколько разных процессов. У каждого процесса есть своя область памяти, где хранятся инструкции, данные, стек, но (за исключением системных процессов) у них нет доступа к памяти других процессов или к памяти системного ядра. [3] В UNIX, как и в почти всех современных системах, может выполняться и обычно выполняется много процессов одновременно. Для общения с системой процессы используют системные вызовы. Доступ к файлам, обмен сигналами между процессами, выделение памяти и проч. производится через системные вызовы.

Каждый процесс имеет свой уникальный номер, называемый PID (process identifier). Узнать PID данного процесса можно системным вызовом getpid.

Список процессов можно посмотреть командой ps. Эта команда имеет множество флагов и работает по-разному в разных UNIX. Другая команда для просмотра списка процессов — top. Убить процесс можно командой kill.

Системный вызов exit завершает текущий процесс, sleep усыпляет его на заданное количество секунд, nanosleep — на заданное количество секунд и наносекунд. Для убийства процесса можно использовать системный вызов kill.

Параметры и окружение

править

Каждый процесс имеет параметры и окружение. Параметры процесса — это массив строк, кончающийся нулевым указателем, называемый обычно argv и передаваемый в первую вызванную функцию. Количество параметров называется argc. Окружение процесса — это массив строк типа ПЕРЕМЕННАЯ=значение, тоже кончающийся нулевым указателем и доступный через глобальную переменную environ, имеющую (в C) тип char** . Посмотреть окружение можно командой printenv [имя] (если имя не указано, выводится всё окружение), а в командной оболочке sh или bash - ещё и встроенной командой

set -p

Изменить переменные окружения в командной оболочке sh или bash можно встроенной командой

export [имя[=значение]] ... [имя[=значение]]

При этом переменные с указанными именами экспортируются в окружение, а если указано значение - оно предварительно им присваивается. Присвоить значение переменной до или после экспорта в командной оболочке sh или bash можно встроенной командой

имя=значение

А посмотреть командой

echo $имя

Отменить экспорт в этих командных оболочках можно командой

export -n имя ... имя

В командной оболочке csh или tcsh окружение независимо от переменных и устанавливается встроенной командой

setenv имя значение

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

unsetenv имя ... имя

Размножение процессов

править

Процессы могут порождать новые процессы. Порождённый процесс называется child process, а процесс, породивший его - parental process. Самым первым процессом является init, его функция — породить остальные процессы, а сам он не имеет родительского процесса. Все остальные процессы являются потомками init. Если пользователь запускает программу, соответствующий процесс порождается командной оболочкой — процессом, основная функция которого — вводить команды с терминала и выполнять их. PID родителя называется PPID и возвращается системным вызовом getppid.

Для порождения новых процессов используются системные вызовы fork и vfork. Системный вызов fork раздваивает текущий процесс, создаёт его клон. Вновь созданный процесс не отличается от старого ничем, кроме PID и PPID. Системный вызов execve запускает исполняемый файл (параметрами его являются исполняемый файл, аргументы и переменные окружения). Вновь запущенный исполняемый файл заменяет собой текущий процесс. Таким образом, fork сохраняет исполняемый файл, но меняет PID и PPID, а execve - наоборот.

Поскольку fork и execve часто вызываются в тандеме, полезен системный вызов vfork: он гораздо быстрее, чем fork, но всё, что после него можно сделать — вызвать execve.

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

Если родительский процесс умер, его процесс-сын становится сиротой, после чего усыновляется процессом init.

Виды процессов

править

Есть три вида процессов:

  • Системные процессы. Часто их не относят к процессам. У них нет исполняемого файла и они работают в режиме ядра, то есть могут то, что никаким другим процессам не разрешается, например, непосредственно писать и читать с диска в обход файловой системы или получать доступ к памяти других процессов. Первым системным процессом является init: его функция — породить все остальные. Примерами других системных процессов являются
    • диспетчер свопинга swapper или sched — выгружает давно не используемые регионы памяти на диск (в область для свопинга) и, напротив, подгружает с диска то, что понадобилось в данный момент. Благодаря свопингу процессы могут получать больше памяти, чем физически есть в компьютере: то, что в данный момент не нужно, хранится на диске.
    • диспетчер страничного замещения vhand: освобождает страницы памяти (page stealing daemon).
  • Демоны. Это уже настоящие процессы, они имеют исполняемый файл. Демоны работают в фоновом режиме без прямого общения с пользователем. Они обеспечивают работу принтеров, интернета и т. д. Системные процессы часто тоже называют демонами. Типичный список демонов и системных процессов приведён в статье Список UNIX-демонов.
  • Прикладные процессы - все остальные. В результате запуска исполняемых файлов пользователем возникает прикладной процесс.

Состояния процессов

править

В простейшем случае каждый процесс может находится в одном из трёх состояний:

  • Выполняемый.
  • Остановленный — процесс спит или ждёт системных ресурсов.
  • Зомби — процесса больше нет, но запись о нём в списке процессов по каким-то причинам пока что осталась. Часто это происходит из-за того, что родительский процесс ещё не получил результаты его выполнения.

Подробнее о состояниях процессов можно почитать здесь.

Владельцы

править

Подобно тому как каждый файл имеет владельца и группу-владельца, процессы тоже имеют своих владельцев.

  • идентификатор пользователя UID (user identifier) и идентификатор группы GID (group identifier) — наследуются от родительского процесса. Иногда называются RUID и RGID (R означает real).
  • действующий идентификатор пользователя EUID и действующий идентификатор группы EGID (E означает effective) — наследуются от исполняемого файла, если для него установлен бит s. В противном случае совпадают с UID, GID. Именно от них зависит, какие права у этого процесса.
  • сохранённый идентификатор пользователя SUID и сохранённый идентификатор группы SGID (S означает saved) — сохраняют UID, GID при их изменении, чтобы система разрешила изменить их обратно.

Права, которые имеет процесс, определяются его EUID, EGID. UID, GID нужны, чтобы процесс знал, кто его запустил на самом деле: благодаря этому, например, программа passwd может менять пароль запустившему её пользователю, а больше никому. Кроме того, процесс может поменять свои EUID, EGID на UID, GID.

Посмотреть владельцев процесса можно системными вызовами getuid, getgid, geteuid, getegid, а изменить их - вызовами setuid, setgid, seteuid, setegid, setreuid, setregid. Правила того, какие изменения владельцев процесса разрешены, довольно сложны и описаны в man соответствующих функций [1].

Группы и сеансы

править

Процессы объединяются в группы процессов, а группы процессов — в сеансы (sessions). Сеансу соответствуют все процессы, созданные пользователем за сеанс работы (с момента входа в систему до момента выхода). Узнать идентификатор группы процессов можно системными вызовами getpgrp (для текущего процесса) или getpgid (для любого процесса), а идентификатор сеанса - системным вызовом getsid. Не суперпользователь может вызывать getpgid и getsid только для процессов из того же сеанса. Изменить группу, тем самым присоедив процесс к другой существующей или создав новую, можно системным вызовом setpgid — это можно сделать для текущего процесса или его потомков, кроме тех, которые изменили свой выполняемый файл системным вызовом exec. Создать новый сеанс и сделать процесс его лидером можно вызовом setsid, но перевести процесс в другой существующий сеанс нельзя.

Лидером группы или сеанса называется процесс, создавший эту группу или сеанс. Лидер группы может её покинуть, при этом группа сохранится. Лидер сеанса не может покинуть его вызовом setsid. При завершении работы лидера сеанса всем процессам этого сеанса, кроме находящихся в фоновом режиме, будет отправлен сигнал SIGHUP (подробнее о сигналах см. ниже), и они завершатся.

Многие системные вызовы, например kill и waitpid, работают не только с отдельными процессами, но и с группами процессов.

Чтобы демонизировать процесс (сделать его демоном), нужно создать новый сеанс вызовом setsid.

Приоритеты

править

Каждый процесс имеет приоритет (nice value). Приоритет — это целое число, часто от -20 до 19, по умолчанию 0. Чем больше число, тем ниже приоритет. При конкуренции процессов за время процессора и другие ресурсы предпочтение отдаётся процессам с высшим приоритетом (т. е. с меньшим числом). Процесс может поменять приоритет себе, используя системный вызов nice. Системные вызовы getpriority, setpriority определяют или меняют приоритеты любых процессов или групп процессов. Смотреть приоритеты чужих процессов может любой. Не суперпользователь может менять приоритеты только своих процессов, и не выше константы, которая называется NZERO. (Строго говоря, каждый пользователь имеет максимальный приоритет, выше которого ему нельзя устанавливать приоритеты своих процессов. Изменить максимальный приоритет любого пользователя может суперпользователь с помощью всё того же системного вызова setpriority).

Запустить процесс с пониженным (или, для суперпользователя, с повышенным) приоритетом можно командой

nice [-###] команда [аргументы] или nice [-n ###] команда [аргументы]

Приоритет команды снижается на ###, по умолчанию на 10.

Изменить приоритет уже запущенного процесса или группы процессов можно командой renice.

Сигналы

править

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

Процесс может реагировать на сигнал тремя способами:

  • обработать его по умолчанию (чаще всего обработка по умолчанию означает «убей процесс»)
  • игнорировать, или блокировать, сигнал (некоторые сигналы блокировать нельзя)
  • перехватывать сигнал, то есть установить свой собственный способ обработки сигнала (некоторые сигналы перехватывать нельзя)

Изменить маску игнорирования сигналов можно системным вызовом sigprocmask, изменить способ обработки сигналов - системным вызовом sigaction. Есть ещё системный вызов sigpending (посмотреть, какие заблокированные сигналы получены) и sigsuspend (временно измени маску и жди определённый сигнал). Подробнее об этих системных вызовах — см. в man sigaction на opennet.ru.

Послать сигнал sig любому процессу можно системным вызовом kill(pid, sig), а текущему - системным вызовом raise(sig). Из командной оболочки сигналы посылаются командой

kill -sig pid ...

Наиболее важными сигналами являются 9 и 15, убивающие процесс. Сигнал 9 (SIGKILL) нельзя перехватывать и игнорировать, а сигнал 15 (SIGTERM) — можно. Зомби не убиваются.

Список сигналов

править

Здесь приведены сигналы, стандартные для POSIX.1. Там, где приведены 3 разных значения, значение сигнала зависит от архитектуры. Подробнее о зависимости значения от архитектуры и нестандартных сигналах см. man signal в opennet.ru.

имя значение действие по умолчанию название сигнала примечания
SIGHUP 1 убить процесс Процесс-лидер сеанса завершил выполнение
SIGINT 2 убить процесс Прерывание с клавиатуры
SIGQUIT 3 убить процесс, записать дамп Выход с клавиатуры
SIGILL 4 убить процесс, записать дамп Несуществующая инструкция
SIGTRAP 5 убить процесс Трассировочное прерывание (для отладчика)
SIGABRT 6 убить процесс, записать дамп Сигнал прерывания, посланный функцией abort
SIGFPE 8 убить процесс, записать дамп Ошибка операций с плавающей запятой
SIGKILL 9 убить процесс Kill-сигнал нельзя блокировать и перехватывать
SIGSEGV 11 убить процесс, записать дамп Обращение к запретной области памяти
SIGPIPE 13 убить процесс Оборванный канал: запись в канал, из которого не читают
SIGALRM 14 убить процесс Сигнал таймера от функции alarm
SIGTERM 15 убить процесс Сигнал завершения
SIGUSR1 30,10,16 убить процесс Первый сигнал, определяемый пользователем
SIGUSR2 31,12,17 убить процесс Второй сигнал, определяемый пользователем
SIGCHLD 20,17,18 ничего не делать Потомок остановлен или прекратил выполнение
SIGCONT 19,18,25 - Продолжить выполнение, если остановлен
SIGSTOP 17,19,23 приостановить выполнение процесса Приостановить выполнение процесса нельзя блокировать и перехватывать
SIGTSTP 18,20,24 приостановить выполнение процесса Останов введен с терминала
SIGTTIN 21,21,26 приостановить выполнение процесса ввод с терминала у фонового процесса
SIGTTOU 22,22,27 приостановить выполнение процесса вывод на терминал у фонового процесса

Лимиты

править

Процессы имеют лимиты системных ресурсов (количества одновременно открытых файлов, памяти и проч.) Узнать или изменить эти лимиты можно системными вызовами getrlimit и setrlimit соответственно [2].

Основные системные вызовы для работы с процессами

править

Системныe вызовы getpid, getppid возвращают PID текущего процесса и его родительского процесса.

Системный вызов fork раздваивает текущий процесс, создаёт его клон. Вновь созданный процесс не отличается от старого ничем, кроме PID и PPID.

Системный вызов exec запускает исполняемый файл (параметрами его являются исполняемый файл и аргументы). Вновь запущенный исполняемый файл заменяет собой текущий процесс.

Поскольку fork и exec часто вызываются в тандеме, полезен системный вызов vfork: он гораздо быстрее, чем fork, но всё, что после него можно сделать — вызвать exec.

Системный вызов wait ждёт, пока процесс-ребёнок не закончит свою работу.

Системный вызов waitpid ждёт того же для любого процесса (параметром его является PID этого процесса).

Системный вызов exit завершает текущий процесс.

Системный вызов sleep усыпляет текущий процесс на заданное количество секунд, а nanosleep - на заданное количество секунд и наносекунд.

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

Посмотреть владельцев процесса можно системными вызовами getuid, getgid, geteuid, getegid, а изменить их - вызовами setuid, setgid, seteuid, setegid, setreuid, setregid.

Командный интерпретатор

править

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

Командный интерпретатор также может выполнять команды и из файла - такие файлы называют скриптами.

Есть около полудюжины распространённых командных интерпретаторов, каждый пользователь может выбрать себе по вкусу. Любимый командный интерпретатор каждого пользователя находится в файле /etc/passwd, а изменить его можно командой chsh (change shell). Список допустимых командных интерпретаторов находится в файле /etc/shells, и выбирать свой можно только из этого списка. Это сделано потому, что если пользователь сделает командным интерпретатором неправильный файл, он больше не сможет работать в системе, не сможет и изменить командный интерпретатор обратно.

Первый командный интерпретатор назывался sh (Bourne shell - по имени своего создателя, или просто shell) и появился в районе 1978 года. Его продвинутая версия называется bash (Bourne again shell) и используется чаще, чем старая версия.

Командный интерпретатор csh (C shell) может вычислять выражения (особенно арифметические) с Си-подобным синтаксисом, отсюда название. Его продвинутая версия называется tcsh и отличается прежде всего развитыми средствами редакции командной строки.

Кроме того, существуют ksh (Korn shell) и zsh.

Командные интерпретаторы находятся в директории /bin.

Полную инструкцию к любому командному интерпретатору можно посмотреть командой man (а именно man sh, man csh и т. д.)

Запуск команд

править

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

ls -l /

вызовет файл /bin/ls (если каталог /bin указан в PATH и команда ls не найдена в других каталогах из PATH) с параметрами -l и /

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

Скрипты

править

Если файл начинается со строки, подобной

#!/bin/sh

(вместо /bin/sh может стоять любой исполняемый файл), он считается скриптом. При запуске такого файла (назовем его pupkin) на исполнение, запускается указанный исполняемый файл и первым параметром ему передается имя выполняемого файла (т.е. в данном случае /bin/sh pupkin).

Смена и вывод текущего каталога

править

Осуществляется во всех командных интерпретаторах встроенной командой

cd каталог

или просто

cd

Если каталог не указан, текущим каталогом становится домашний каталог пользователя. Вывести текущий каталог можно командой

pwd

Тильда

править

Если параметр начинается с тильды, во всех командных интерпретаторах эта тильда заменяется на домашний каталог. Например, команда

ls ~

выдаёт содержимое вашего домашнего каталога, а команда

ls ~/Foo

выдаёт содержимое подкаталога Foo в вашем домашнем каталоге.

Раскрытие шаблонов (pattern matching, filename substitution)

править

Раскрытие шаблонов - ещё механизм, действующий практически одинаково во всех командных интерпретаторах. Если параметр команды содержит что-то из следующего: звёздочку (*), вопросительный знак (?), пару квадратных скобок ([...]), он считается шаблоном и заменяется списком всех файлов, удовлетворяющим этому шаблону.

  • Звёздочка соответствует любой (в том числе пустой) последовательности символов.
  • Вопросительный знак соответствует любому одному символу.
  • Пара квадратных скобок с символами между ними (например, [123ах]) соответствует любому из этих символов.
    • Конструкция с12 между квадратными скобками означает любой символ от с1 до с2 (в порядке ASCII).
    • Если в список символов нужно включить минус, его надо сделать первым или последним, а закрывающую квадратную скобку - первой.
    • Если список символов начинается со шляпки (^), он соответствует любому символу, не содержащемуся в нём.
  • Файлы, чьё имя начинается с точки, удовлетворяют только такому шаблону, где эта точка указана явно. (Они невидимы для команды ls, и так же невидимы для командной оболочки.)

Примеры.

  • echo * выдаёт все файлы в текущем каталоге, кроме начинающихся на точку (.)
  • echo a*.c выдаёт все файлы в текущем каталоге, начинающиеся на a и кончающиеся на .c
  • echo */*/* выдаёт файлы во всех каталогах, которые содержатся во всех каталогах, которые содержатся в текущем каталоге (опять же, каталоги и файлы, чьё имя начинается на точку, не считаются).
  • echo [A-Za-z]?[^0-9]* выдаёт все файлы в текущем каталоге, первый символ имени которых - латинская буква, а третий - не цифра.

Если шаблону не удовлетворяет ни один файл, иногда выдаётся ошибка (так поступает по умолчанию csh и tcsh), иногда, как в bash, шаблон остаётся нераскрытым. Чтобы изменить такое поведение, в bash надо установить переменную nullglob (при этом неудовлетворённый шаблон превращается в пустое место), а в csh - переменную nonomatch (при этом шаблон остаётся нераскрытым, как в bash).

В большинстве командных интерпретаторов есть дополнительные возможности раскрытия шаблонов. В каждом командном интерпретаторе они свои и их, как и все остальные возможности командного интерпретатора, можно посмотреть командой man в разделе, который обычно называется pattern matching или filename substitution.

Фигурные скобки

править

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

echo a{1,,2}{a,b,cc}

выдаст (независимо от того, какие файлы есть в текущей директории)

a1a a1b a1cc aa ab acc a2a a2b a2cc

Кавычки и обратный слеш

править

Обратный слеш (\) экранирует следующий символ (т. е. лишает его специального смысла). Одинарные кавычки экранируют всё, кроме обратного слеша и одинарных кавычек. Двойные - всё, кроме обратного слеша, двойных кавычек, и знака доллара ($). Кавычки и обратный слеш полезны, в частности, если имя файла имеет пробелы внутри:

cat 'vasya pupkin jjot.txt'

Обратные кавычки имеют специальный смысл. То, что между обратными кавычками, интерпретируется как команда; она выполняется, и её стандартный вывод подставляется вместо неё, например

ls -l `cat spisok_failov`

выводит информацию обо всех файлах, имена которых содержатся в файле spisok_failov.

Ctrl-C и другие символы

править

Нажатие клавиши Ctrl-C останавливает выполнение текущей команды, посылая ей сигнал SIGINT. Ctrl-Z приостанавливает текущую команду, переводя её в режим сна. Разбудить её можно командой %%.

Стандартный ввод и вывод

править

Каждый процесс имеет стандартный ввод (stdin) и стандартный вывод (stdout). Переадресовать стандартный ввод или вывод можно с помощью конструкции >файл (вывод) или <файл (ввод). А ещё можно стандартный вывод одной команды направить в стандартный ввод другой с помощью конструкции команда|команда. Это называется конвейер. В общем виде конвейер выглядит так:

команда | команда | ... | команда < файл > файл

Конструкции <файл и >файл являются необязательными, независимыми друг от друга, и могут быть в любом порядке. Пробелы неважны.

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

Кроме стандартного ввода и стандартного вывода, есть и стандартная диагностика (stderr, standard error). Разные интерпретаторы по-разному позволяют переадресовать её. Так, в csh и tcsh для переадресации и стандартного вывода, и стандартной диагностики используется конструкция |&файл, >&файл или >>&файл, а переадресовать только одну стандартную диагностику невозможно.

Многие команды в UNIX часто используются, или даже в основном предназначены, для работы в конвейере. Наиболее типичной такой командой является less (и её более старая версия more), которая позволяет просматривать стандартный вывод любой команды. Другими такими командами, по-видимому, являются sed, grep, sort.

Комментарии

править

Всё, что идёт в строке после решётки (#), считается комментарием..

Файлы и каналы

править
Пример использования именного потока.

Сноски

править
  1. Строго говоря, файлы создают не пользователи, а процессы. Соответственно, файл наследует от процесса идентификатор пользователя EUID, а в BSD - и идентификатор группы EGID
  2. в некоторых UNIX-ах может называться иначе
  3. w:Microsoft реализовало этот принцип начиная с w:Windows NT, сделав свою Windows гораздо надёжнее, чем раньше.