В момент своего создания в 1970-х годах Unix был очень простой ОС, созданной как один большой хак. Многие детали внутреннего устройства UNIX появились на свет просто по тому, что у авторов не было времени и желания писать сложный код там, где можно было обойтись временной "затычкой". К сожалению, в тот момент когда Unix стал популярной системой, одновременно произошли две вещи - а) стало понятно, что многие архитектурные решения, заложенные в Unix, не годятся для реальной ОС и б) уже ничего нельзя сделать не потеряв совместимости с существующими программами.
Ниже приведен конспект книги The UNIX-HATERS Handbook под редакцией Simson Garfinkel, Daniel Weise и Steven Strassmann, опубликованной IDG Books в 1994 году. За последние двадцать лет несколько из упомянутых в книге ошибок были сглажены, но в целом ситуация в мире Unix/Linux осталась прежней, поскольку слабость Unix'а заложена в самых базовых его концепциях.
"Два самых знаменитых продукта, вышедших из стен университета в Беркли, это LSD и Unix. И похоже что это не случайное совпадение" (Anonymous)
Unix это вирус - он маленький, переносимый, жрёт ресурсы хозяина, быстро мутирует.
Unix это наркотик. Как опытный наркоделец AT&T раздавала первые версии бесплатно.
Что означают названия языков C и C++? Это оценки. (В США оценки обозначаются буквами А - отлично, В - хорошо, С - так себе).
Мифы о Unix'е
Мистические имена
На ранних этапах разработки Unix в качестве терминала использовалась электрическая пишущая машинка - телетайп. Поскольку по клавишам приходилось бить с большой силой, программисты старались давать командам загадочные, но короткие имена - rm
, cp
, wc
и т.п. Теперь ситуация изменилась, многие используют оконные системы и оболочки с автодополнением, но переименовать команды во что-то более осмысленное уже нельзя, не потеряв совместимость с миллионами накопленных скриптов.
Случайная порча данных в Unix'е
del *.*
выдаёт предупреждение пользователю, в Unix невозможно отличить rm *
от rm file1 file2 file3...
Примеры:
Опечатка rm *>o
вместо rm *.o
уничтожит все файлы в каталоге и создаст пустой файл "o" . Лишний пробел в rm * .o
также приведёт к печальным последствиям.
Удаление администратором подкаталога, совпадающего по имени со стандартным - опасно. Вместо rm -r ./etc
легко напечатать rm -r /etc
, что убьёт систему. Unix не предусматривает особой защиты для системных каталогов.
Замена rm
на альяс rm -i
или на что-то совсем другое (например mv $@ ~/.Deleted
) не является панацеей, т.к. не влияет на команды удаления файлов, встроенные в оконную систему, среду разработки и т.п. Кроме того использование альяса может нарушить работу скриптов (скрипт начнёт запрашивать подтверждения) и сбить с толку сисадмина, который будет пытаться понять, почему у пользователя неверно работает программа.
Команда rm *
, выполненная в одном каталоге, сохраняется в истории команд и может быть случайно вызвана в другом подстановкой !r
(последняя команда в истории на букву r).
Удаление файла с именем "*" - отдельное искусство.
Отсутствие стиля как стиль
Программы в Unix не имеют общего стиля. Каждый волен придумать свой набор опций, свой конфигурационный файл и свою систему оповещения об ошибках. Не существует требования по использованию определённых библиотек. Так ed
, sed
, grep
и shell
имеют схожие, но различные форматы регулярных выражений.
Заявленная философия простоты и самодостаточности отдельных утилит (делает мало, но делает хорошо) в реальном Unix'е не соблюдается. Простейшая команда cat
, изначально предназначенная для объединения содержимого нескольких файлов в один поток, имеет несколько опций, которые предполагают, что команда используется для просмотра содержимого файла на терминале.
С другой стороны плодятся лишние программы. Вместо программы, вырезающей несколько строк из середины файла, существуют программы head
- вырезание строк из начала файла и tail
- вырезание из хвоста. Программы написаны разными авторами имеют разный набор опций.
Уже упоминалось, что подстановка "*" при обработке шеллом (вместо использования стандартной функции в самой программе) приводит к потере части информации о командной строке. В сочетании с тем, что Unix не отличает в командной строке имена файлов от опций, это приводит к катастрофическим последствиям. Имена файлов, начинающиеся с "-" нельзя отличить от опций. Например, команда rm *
в каталоге, содержащем файл "-r" приведёт к рекурсивному удалению подкаталогов, но сохранит сам файл "-r".
Обратная ситуация. Некоторые утилиты могут воспринимать имена файлов, начинающиеся с "-" как неверные опции и не смогут обработать такие файлы:
$ mv -file file
mv: invalid option -- l
$ rm -file
usage: rm [-rif] file ...
$ rm ?file
usage: rm [-rif] file ...
$ rm ?????
usage: rm [-rif] file ...
$ rm *file
usage: rm [-rif] file ..
(В современном Linux'е выдаётся подсказка Try 'rm ./-file' to remove the file '-file', но само поведение команды не изменилось).
MAN-страница по rm
в Linux'е предлагает использовать rm -- -foo
для удаления -foo, но это не является частью стандарта. Авторам оригинальной книге в MANе предложили использовать rm - -foo
.
Шутка с ls
. Готовим каталог и файл
% mkdir foo
% touch foo/foo~
Теперь зовём ничего не подозревающего соседа и просим объяснить результат выполнения команд
% ls foo*
foo~
% rm foo~
rm: foo~ nonexistent
% rm foo*
rm: foo directory
% ls foo*
foo~
%
Попробуйте объяснить, что делает команда cat - - -
(подсказка: тройное нажатие ^D завершит её работу).
Электронная документация
Основой электронной документации в Unix являются man-страницы. К сожалению, часть команд являются исполняемыми файлами (wc,ls,rm), а часть встроенными командами шелла (fg,job,alias). man-страницы описывают внешние команды и шелл в целом. Если новичок не знает какой у него шелл, он не сможет добраться до описания встроенных команд.
Предупреждения и сообщения об ошибках в Unix - ИХ НЕТ!
Ошибка в порядке написания имён файлов cc -o prog.c prog
вместо cc -o prog prog.с
при запуске компилятора молча уничтожит исходные тексты. Ошибка в опциях архиватора tar cf bigarchive.tar
вместо tar xf bigarchive.tar
молча уничтожит архив.
Управление терминалом
То, что ранние версии Unix'а разрабатывались на компьютере с примитивным телетайпом в качестве терминала, привело к тому, что в ядре Unix'а вообще отсутствуют средства для работы с интеллектуальными средствами взаимодействия с пользователями.
Телетайпы умели построчно печатать текст и (по приходу специального символа) переходить на следующую строку (NL \n), возвращать каретку в начало строки (CR \r) и звенеть звонком (BELL \b). После телетайпов на рынок вышли текстовые видео терминалы, которые выводили текст существенно быстрее и позволяли (с помощью управляющих последовательностей символов) проделывать разные трюки с текстом на экране. К сожалению, у разных производителей управляющие последовательности были разными.
Бил Джой во время разработки редактора vi создал базу управляющих последовательностей - termcap
, которая позволяла извлекать последовательности, выполнявшие определённые функции на конкретном терминале. К сожалению termcap отражала не те функции, которые были придуманы производителями, а те которые были нужны для работы редактора vi
. (В последующем набор функций был несколько расширен, но сути дела это не меняет). Кроме того, код работавший с termcap в vi
так и не был оформлен в отдельную библиотеку, что заставляло программистов самостоятельно изобретать собственные API.
В конце концов Кен Арнольд написал библиотеку для управления текстовым терминалом под названием curses
. К сожалению, библиотека ориентировалась на ту же урезанную базу терминальных функций termcap и к тому же была не очень профессионально написана. В результате curses стала полустандартом в мире Unix. В книге есть фраза: ...и сейчас в 1994 году стандарта управления терминалом по прежнему нет. Нет его и двадцать лет спустя.
Вместо того, чтобы включить в ядро вызовы для манипулирования с абстрактным терминалом, разработчики Unix'а вынесли всю логику в относительно стандартные библиотеки или вообще зашили работу с терминалом в код программ. В первую очередь такой подход лишил Unix-программы совместно использовать один экран. Кроме того, в Unix (отчасти из из за идеи, что всё есть последовательный файл, а отчасти из за ограничений termcap
и curses
) никогда не была реализована работа с "умными" терминалами, которые позволяют создавать экранные формы, рисовать изображения и т.п.
Даже в тех случаях, когда можно было программно реализовать любой механизм управления экраном, например в виртуальной консоли Linux или в графическом оконном терминале xterm
, разработчики шли по пути эмуляции относительно примитивного текстового терминала vt100. И всё это лишь для того, чтобы обеспечить совместимость с редактором vi
.