UNIX-подобные системы содержат кучу костылей. Крах «философии UNIX»

    UPD от 2017-03-04: кто-то выполнил английский перевод. Обсуждение на Hacker News.

    В первой части статьи перечислю кучу костылей UNIX, и вообще разных недостатков. Во второй — про «философию UNIX». Статья написана наскоро, «полировать» дальше не хочу, скажите спасибо, что написал. Поэтому многие факты привожу без ссылок.

    Костыли в UNIX начали возникать ещё с момента появления UNIX, а это было ещё раньше появления не только Windows, но даже вроде бы Microsoft DOS (вроде бы, мне лень проверять, проверяйте сами). Если лень читать, хотя бы просмотрите все пункты, что-нибудь интересное найдёте. Это далеко не полный список, это просто те косяки, который я захотел упомянуть.

    • В самом начале make был программой, которую один человек написал для себя и нескольких своих знакомых. Тогда он, недолго думая, сделал так, что командами воспринимаются строки, которые начинаются с Tab. Т. е. Tab воспринимался отлично от пробела, что крайне некрасиво и нетипично ни для UNIX, ни за его пределами. Он так сделал, потому что не думал, что make будет ещё кто-то использовать кроме этой небольшой группы. Потом появилась мысль, что make — хорошая вещь и неплохо бы включить его в стандартный комплект UNIX. И тогда чтобы не сломать уже написанные мейкфайлы, т. е. написанные вот этими вот десятью людьми, он не стал ничего менять. Ну вот так и живём… Из-за тех десятерых страдаем мы все.

    • Почти в самом начале в UNIX не было папки /usr. Все бинарники размещались в /bin и /sbin. Но потом вся инфа перестала помещаться на тот диск, который был в распоряжении авторов UNIX (Томпсон, Ритчи). Поэтому они достали ещё один диск, создали папку /usr, а в ней — ещё один bin и ещё один sbin. И смонтировали новый диск в /usr. Оттуда и пошло. Так появилась «вторая иерархия» /usr, а потом в какой-то момент ещё и «третья иерархия» /usr/local, а потом ещё и /opt. Как пишет рассказчик этой истории: «Не удивлюсь, если когда-нибудь ещё появится /opt/local». UPD от 2017-02-12: я нашёл ссылку, где я почерпнул эту историю. Читайте, там более точная версия произошедшего.

    • sbin изначально означало «static bin», а не «superuser bin», как можно было бы подумать. И содержал sbin статические бинарники. Но потом sbin стал содержать динамические бинарники, его название потеряло смысл.

    • Windows часто ругают за наличие реестра и сообщают при этом, что подход UNIX-подобных систем (куча конфигов) якобы лучше. А между прочим однажды в ext4 появилась особенность (является ли это багом, вопрос спорный), из-за которой при резком выключении компа Gnome потерял все свои конфиги в рабочей папке юзера. И разработчик этой ext4 сказал в обсуждении баг репорта, что Gnome'у надо было использовать что-то вроде реестра для хранения инфы.

      UPD от 2017-02-12: источники: раз и два. Имя отписавшегося maintainer'а ext4: Theodore Ts'o. Вот его слова:

      If you really care about making sure something is on disk, you have to use fsync or fdatasync. If you are about the performance overhead of fsync(), fdatasync() is much less heavyweight, if you can arrange to make sure that the size of the file doesn't change often. You can do that via a binary database, that is grown in chunks, and rarely truncated.

      I'll note that I use the GNOME desktop (which means the gnome panel, but I'm not a very major desktop user), and «find .[a-zA-Z]* -mtime 0» doesn't show a large number of files. I'm guessing it's certain badly written applications which are creating the «hundreds of dot files» that people are reporting become zero lengh, and if they are seeing it happen a lot, it must be because the dot files are getting updated very frequently. I don't know what the bad applications are, but the people who complained about large number of state files disappearing should check into which application were involved, and try to figure out how often they are getting modified. As I said, if large number of files are getting frequently modified, it's going to be bad for SSD's as well, there are multiple reasons to fix badly written applications, even if 2.6.30 will have a fix for the most common cases. (Although some server folks may mount with a flag to disable it, since it will cost performance.)

      И это не говоря уж о том, что критичные файлы UNIX (такие как /etc/passwd), которые читаются при каждом (!) вызове, скажем, ls -l, записаны в виде простого текста. И эти файлы надо заново читать и заново парсить при каждом вызове ls -l! Было бы гораздо лучше использовать бинарный формат. Или БД. Или некий аналог реестра. Как минимум, для вот таких вот критичных для производительности ОС файлов.

    • Two famous people, one from MIT and another from Berkeley (but working on Unix) once met to discuss operating system issues. The person from MIT was knowledgeable about ITS (the MIT AI Lab operating system) and had been reading the Unix sources. He was interested in how Unix solved the PC loser-ing problem. The PC loser-ing problem occurs when a user program invokes a system routine to perform a lengthy operation that might have significant state, such as IO buffers. If an interrupt occurs during the operation, the state of the user program must be saved. Because the invocation of the system routine is usually a single instruction, the PC of the user program does not adequately capture the state of the process. The system routine must either back out or press forward. The right thing is to back out and restore the user program PC to the instruction that invoked the system routine so that resumption of the user program after the interrupt, for example, re-enters the system routine. It is called «PC loser-ing» because the PC is being coerced into «loser mode,» where «loser» is the affectionate name for «user» at MIT.

      The MIT guy did not see any code that handled this case and asked the New Jersey guy how the problem was handled. The New Jersey guy said that the Unix folks were aware of the problem, but the solution was for the system routine to always finish, but sometimes an error code would be returned that signaled that the system routine had failed to complete its action. A correct user program, then, had to check the error code to determine whether to simply try the system routine again. The MIT guy did not like this solution because it was not the right thing.

      The Rise of «Worse is Better» By Richard Gabriel

      Если кратко и своими словами, то в начале разработки UNIX авторы UNIX решили попросту выдавать ошибку из ядра пользовательской программе, если пользовательская программа прервана по сигналу, и на этот сигнал повешен обработчик. Иными словами, если вы перехватили Ctrl-C (т. е. поставили на него обработчик) в своей программе, а юзер за терминалом нажал этот самый Ctrl-C, то ОС выполнит обработчик, а потом вместо простого продолжения того сисвызова, который выполнялся в момент Ctrl-C, просто прервёт его, вернув из ядра в пользовательскую программу EINTR. В результате программисту, пишущему эту программу придётся эту EINTR предусмотреть. А это усложняет этот userspace код. Ценой упрощения кода ядра. Да, нужно было сделать по-другому. Усложнить код ядра и упростить userspace код, который придётся писать всем программистам. Но тому человеку из Беркли из цитаты выше было пофигу. Он фактически сказал: «Да мне пофиг, что все будут страдать, главное, чтоб код ядра попроще был».

      Дальше — больше. Позже в UNIX-системах всё же пофиксили упомянутую особенность, добавив так называемый SA_RESTART. То есть вместо того, чтобы просто всё пофиксить, они добавили специальный флаг. Так мало того, что они это сделали, этот SA_RESTART ещё и не всегда работает! В частности, в GNU/Linux select, poll, nanosleep и др. не продолжают свою работу после перехваченного прерывания даже в случае SA_RESTART!

    • Вообще, конкретные обстоятельства, возникшие во время разработки оригинальной UNIX, сильно оказали на неё влияние. Скажем, читал где-то, что команда cp названа именно так, а не copy, потому что UNIX разрабатывали с использованием терминалов, которые очень медленно выдавали буквы. А потому набрать cp было быстрее, чем copy. UPD от 2017-02-12: найти именно ту ссылку, которую я видел когда-то давно, и в которой приводился пример с cp и copy, мне не удалось. Но есть, например, вот эта ссылка.

      Commands — Are These Real Words?

      The basic AIX commands (and all UNIX system commands) are, for the most
      part, very short, cryptic, two-letter command names. Imagine back years ago,
      when computers had only very slow teletype keyboards and paper “displays.”
      (Some of us aren’t imagining, we’re remembering!) Imagine also, people who
      didn’t like typing long commands because there was such a long delay between
      commands and the computer response. If there were any mistakes, the user had
      to retype the whole thing (especially aggravating for folks that type with only
      two fingers!).

      Also, some UNIX commands came from university students and researchers who
      weren’t bound by usability standards (no rules, merely peer pressure). They
      could write a very useful, clever command and name it anything—their own initials,
      for example (awk by Aho, Weinberger, and Kernighan), or an acronym
      (yacc, Yet Another Compiler-Compiler).

    • Вообще, названия утилит UNIX — это отдельная история. Скажем, название grep идёт от командй g/re/p в текстовом редакторе ed. (Ну а cat — от concatenation, я надеюсь, это все и так знали :) Ну и для кучи: vmlinuz — gZipped LINUx with Virtual Memory support).

    • printf внезапно является далеко не самым быстрым способом вывода информации на экран или в файл. Не знали, да? А дело в том, что printf, как и сама UNIX в целом, был придуман не для оптимизации времени, а для оптимизации памяти. printf каждый раз парсит в рантайме строку формата. Именно поэтому в веб сервере H2O был придуман специальный препроцессор, который переносит парсинг строки формата на этап компиляции.

      UPD от 2017-02-12: источник.

    • Когда Кена Томпсона, автора UNIX (вместе с Деннисом Ритчи) спросили, что бы он поменял в UNIX, он сказал, что назвал бы функцию creat (sic!) как create. UPD от 2017-02-12: источников полно, например этот. No comments. Замечу, что позже этот же Кен Томпсон вместе с другими разработчиками оригинальной UNIX создал систему Plan 9, исправляющую многие недостатки UNIX. И в ней эта функция называется create :) Он смог :)

    • Ещё одна цитата:

      A child which dies but is never waited for is not really gone in that it still consumes disk swap and system table space. This can make it impossible to create new processes. The bug can be noticed whenseveral & separators are given to the shell not followed by ancommand without an ampersand. Ordinarily things clean themselves upwhen an ordinary command is typed, but it is possible to get into asituation in which no commands are accepted, so no waits are done;the system is then hung.The fix, probably, is to have a new kind of fork which creates aprocess for which no wait is necessary (or possible); also to limit the number of active or inactive descendants allowed to a process.

      Источник

      Это цитата из очень раннего манула UNIX. Уже тогда существование зомби-процессов признавалось багом. Но потом на этот баг попросту забили. Понятное дело, что гораздо позже эта проблема всё же была решена. Т. е. в современном GNU/Linux инструменты для убивания зомби-процессов всё же существуют. Но о них мало кто знает. Обычном kill'ом зомби не убиваются. Про существование зомби-процессов все говорят: «It's for design».

    • Ещё немного про уже упомянутый язык C. Вообще язык C разрабатывался одновременно с UNIX, поэтому критикуя UNIX, нужно покритиковать и C тоже. То, что C очень плох, написано много, я не буду повторять все эти аргументы. Там, синтаксис типов плохой, препроцессор ужасен, легко выстрелить себе в ногу, всякие 4["string"], всякие sizeof ('a') != sizeof (char) (в C, не в C++!), всякие i++ + ++i, всякие while (*p++ = *q++) ; (пример из Страуструпа, второе дополненное издание) и так далее и тому подобное.

      Скажу лишь вот что. В C до сих пор не научились удобно работать со строками. Неудобство работы со строками постоянно приводит к разнообразным проблемам безопасности. И эту проблему до сих пор не решили! Вот относительно свежий документ от комитета C. В нём обсуждается весьма сомнительный способ решения проблемы со строками. И делается вывод, что этот способ плох. Год публикации: 2015. То есть даже к 2015-му году окончательного решения ещё нет!

      И это не говоря об отсутствии простой, удобной и мультиплатформенной системы сборки (а не этого монстра autotools, который ещё и не поддерживает винду, и другого монстра cmake, который поддерживает винду, но всё равно монстр), стандартного менеджера пакетов, удобного как npm (js) или cargo (rust), нормальной portability library, с помощью которой можно было кроссплатформенно хотя бы прочитать содержимое папки и хотя бы даже главного сайта C, который был бы главной точкой входа для всех новичков и содержал бы в себе не только документацию, но и краткую инструкцию по установке инструментов C на любую платформу, по созданию простого проекта на C, а также содержал бы удобный поиск по пакетам C (которые должны быть размещены в стандартном репозитории) и, главное, был бы точкой сбора user community. Я даже зарегал домен c-language.org в надежде, что когда-нибудь я создам там такой сайт. Эх, мечты, мечты. (У меня ещё cpp-language.org заныкан, бугога :)) Но всего этого нет. Хоть это и есть у всех популярных языков, кроме C и C++. И даже у Haskell всё это есть. И у Rust.

      У Rust, у этого выскочки, который, кстати говоря, метит в ту же нишу, что и C. Есть единый конфиг, который одновременно является конфигом проекта, конфигом сборки и конфигом для менеджера пакетов (собственно, cargo — это менеджер проектов и система сборки одновременно). Есть возможность указания в качестве зависимости для данного пакета другого пакета, размещённого где-то в *GIT*, в том числе указание в качестве зависимости напрямую программы на *GITHUB*. Генерация из коробки документации из сорцов, записанной в комментах на *MARKDOWN*. И пакетный менеджер, использующий для версий *SEMVER*. Итак, *GIT*, *GITHUB*, *MARKDOWN*, *SEMVER*, короче говоря *BUZZWORDS*, *BUZZWORDS* и ещё раз *HIPSTERS' BUZZWORDS*. И всё сразу из коробки. Прямо вот заходишь на их главный сайт, и вот на тебе на блюдечке с голубой каёмочкой. И работает всё одинаково на всех платформах. Несмотря на то, что Rust — это вроде как язык системного программирования, а не какой-нибудь там javascript. Несмотря на то, что в Rust можно байты гонять. И арифметика указателей там есть. Так почему же у них, у этих выскочек-растовцев, эти хипстерские баззворды есть, а у нас, сишников, их нет? Обыдно.

      Я помню, один знакомый спрашивает у меня, где посмотреть список пакетов для C/C++. Пришлось сказать ему, что такого единого места нет. Он: «Программисты на C/C++ должны страдать?» Мне нечего было ему ответить.

      Ах да, забыл ещё одну вещь. Посмотрите, пожалуйста, на прототип функции signal в том виде, в котором он дан в стандарте C: void (*signal(int sig, void (*func)(int)))(int); и попытайтесь его понять.

    • Терминал в UNIX — жуткое legacy.

    • Имена файлов в файловых системах UNIX (ext2 и пр.) есть просто поток байтов без кодировки. В какой кодировке они будут интерпретированы, зависит от локали. То есть если создать файл на ОС в одной локали, а потом пытаться посмотреть его имя в ОС в другой локали, будет плохо. В виндовом NTFS такой проблемы нет.

    • UNIX shell хуже PHP! Да, да, а вы что, не знали? Сейчас модно ругать PHP. Но ведь UNIX shell ещё хуже :) Особенно плохим он становиться, если пытаться на нём программировать, ведь полноценным языком программирования он не является. Но даже для своей ниши (скриптинг типичных задач по администрированию) он годится плохо. Виной тому примитивность shell, непродуманность, legacy, куча частных случаев, костылей, бардак с кавычками, бекслешами, специальными символами и повёрнутость shell'а (как и всего UNIX) на простом тексте.

      • Начнём с затравки. Как рекурсивно найти в папке foo все файлы с именем \? Правильный ответ таков: find foo -name '\\'. Ну или так: find foo -name \\\\. Последний вариант вызовет особенно много вопросов. Попробуйте объяснить человеку, плохо разбираемущемуся в UNIX shell, почему здесь нужно именно четыре бекслеша, а не два и не восемь (грамотеи, подскажите, как правильно написать это предложение, пишите в личку). А написать здесь нужно четыре бекслеша, потому что UNIX shell делает backslash expanding, и find тоже его делает.

      • Как touch'нуть все файлы в папке foo (и во вложенных)? На первый взгляд, один из способ таков: find foo | while read A; do touch $A; done. Ну, на первый взгляд. На самом деле здесь можно придумать аж 5 нюансов, которые могут испортить нам малину (и привести к проблемам с безопасностью):

        • Имя файла может содержать бекслеш, поэтому нужно писать не read A, а read -r A.
        • Имя файла может содержать пробел, поэтому нужно писать не touch $A, а touch "$A".
        • Имя файла может не только содержать пробел, но и начинаться с пробела, поэтому нужно писать не read -r A, а IFS="" read -r A.
        • Имя файла может содержать перевод строки, поэтому вместо find foo нужно использовать find foo -print0, а вместо IFS="" read -r A нужно использовать IFS="" read -rd "" A (тут я не совсем уверен).
        • Имя файла может начинаться с дефиса, поэтому вместо touch "$A" нужно писать touch -- "$A".

        Итоговый вариант выглядит так: find foo -print0 | while IFS="" read -rd "" A; do touch -- "$A"; done. Круто, да? И здесь мы, кстати, не учли, что POSIX не гарантирует (я не совсем в этом уверен), что touch поддерживает опцию --. Если учитывать ещё и это, то придётся для каждого файла проверять, что он начинается с дефиса (или что не начинается со слеша) и добавлять в начало ./. Теперь вы поняли, почему скрипты configure, генерируемые autoconf'ом такие большие и трудночитаемые? Потому что этому configure нужно учитывать всю эту муть, включая совместимость с разными shell'ами. (В данном примере для демонстрации я использовал решение с пайпом и циклом. Можно было использовать решение с -exec или xargs, но это было бы не так эффектно). (Ладно, хорошо, мы знаем, что имя файла начинается с foo, поэтому оно не может начинаться с пробела или дефиса).

      • В переменной A лежит имя файла, нужно удалить его на хосте a@a. Как это сделать? Может быть так: ssh a@a rm -- "$A" (как вы уже заметили, мы тут уже учли, что имя файла может содержать пробелы и начинаться с дефиса)? Ни в коем случае! ssh — это вам не chroot, не setsid, не nohup, не sudo и не какая-нибудь ещё команда, которая получает exec-команду (т. е. команду для непосредственной передачи сисвызовам семейства execve). ssh (как и su) принимает shell-команду, т. е. команду для обработки shell'ом (термины exec-команда и shell-команда — мои). ssh соединяет все аргументы в строку, передаёт строку на удалённую сторону и там выполняет shell'ом. Окей, может быть так: ssh a@a 'rm -- "$A"'? Нет, эта команда попытается найти переменную A на удалённой стороне. А её там нет, потому что переменные через ssh не передаются. Может, так: ssh a@a "rm -- '$A'"? Нет, это не сработает, если имя файла содержит одинарную кавычку. В общем, не буду вас мучать, правильный ответ таков: ssh a@a "rm -- $(printf '%q\n' "$A")". Согласитесь, удобно?

      • Как зайти на хост a@a, с него — на b@b, с него — на c@c, с него — на d@d, а с него удалить файл /foo? Ну, это легко:

        ssh a@a "ssh b@b \"ssh c@c \\\"ssh d@d \\\\\\\"rm /foo\\\\\\\"\\\"\""
        

        Слишком много бекслешей, да? Ну, не нравится так, давайте чередовать одинарные и двойные кавычки, будет не так скучно:

        ssh a@a 'ssh b@b "ssh c@c '\''ssh d@d \"rm /foo\"'\''"'
        

        А между прочим, если бы вместо shell'а был Lisp, и там функция ssh передавала бы на удалённую сторону не строку (вот она, повёрнутость UNIX на тексте!), а уже распарсенный AST (abstract syntax tree), то такого ада бекслешей не было бы:

        (ssh "a@a" '(ssh "b@b" '(ssh "c@c" '(ssh "d@d" '(rm "foo")))))
        

        «А? Что? Lisp? Что за Lisp?» Интересно, да? На, читайте. И другие статьи Грэма. На русском тоже можно найти.

      • Совместим предыдущие два пункта. Имя файла лежит в переменной A. Нужно зайти на a@a, с него — на b@b, далее на c@c, d@d и удалить файл, лежащий в переменной A. Это я оставляю вам в качестве упражнения :) (Сам я не знаю, как это сделать :) Ну, может, придумаю, если подумаю).

      • echo вроде как предназначен, чтобы печатать на экран строки. Вот только использовать его для этой цели, если строчка чуть сложнее, чем «Hello, world!», нельзя (но см. UPD от 2017-08-01). Единственно верный способ вывести произвольную строку (скажем, из переменной A) таков: printf '%s\n' "$A".

      • Допустим, нужно направить stdout и stderr команды cmd в /dev/null. Загадка: какие из этих шести команд выполняют поставленную задачу, а какие — нет?

        cmd > /dev/null 2>&1
        cmd 2>&1 > /dev/null
        { cmd > /dev/null; } 2>&1
        { cmd 2>&1; } > /dev/null
        ( cmd > /dev/null ) 2>&1
        ( cmd 2>&1 ) > /dev/null
        

        Оказывается, правильный ответ — 1-я, 4-я и 6-я выполняют, 2-я, 3-я и 5-я — не выполняют. Опять-таки, выяснение причин этого оставляется в качестве упражения :)

    • Вообще, этот пост появился в ответ на вот этот пост. Там говорилось, мол, в винде специальная дата используется как метка драйвера от Microsoft. Вместо ввода специального аттрибута или проверки производителя. Особенностей такого рода в UNIX полно. Является ли файл скрытым, выясняется на основе наличия точки в начале файла вместо специального аттрибута. Когда я сам впервые об этом узнал (да, да, в те далёкие времена, когда я впервые поставил Ubuntu), я был шокирован. Я подумал, вот идиоты. А сейчас привык. Но если вдуматься, это жуткий костыль. Далее, shell выясняет, является ли он login shell'ом на основе дефиса, переданного первым символом в argv[0] (?!). Это abuses (ну или misuses, неправильно использует, не знаю, как по-русски сказать) argv[0]. argv[0] не для этого предназначен. Вместо какого-нибудь другого способа. Любой другой способ был бы красивее. Как угодно, любым другим аргументом, переменной окружения.

    • В BSD sockets юзер вынужден сам менять порядок байт у номера порта. А всё потому, что когда-то давно кто-то допустил в коде ядра UNIX ошибку, не предусмотрев смену порядка байт. И в качестве временного хака исправил user space код вместо кода ядра. Так и живём. Оттуда это и в Windows перешло (вместе с файлом /etc/hosts, он же C:\windows\system32\drivers\etc\hosts).

      UPD от 2017-02-12: источник.

    «Философия UNIX». Есть мнение, что якобы UNIX прекрасна и идеальна. Что все её основные идеи («всё есть файл», «всё есть текст» и т. д.) прекрасны и составляют так называемую прекрасную «философию UNIX». Так вот, как вы уже начали догадываться, это не совсем так. Давайте разберём эту «философию UNIX» по пунктам. Сразу скажу: я не хочу сказать, что все пункты нужно отменить, просто я указываю на их неуниверсальность.

    • «Всё есть текст». Как мы с вами уже выяснили на примере /etc/passwd, повсеместное использование простого текста может привести к проблемам с производительностью. И вообще, авторы UNIX фактически придумали для каждого системного конфига (passwd, fstab и так далее) свой формат. Со своими правилами экранирования специальных символов. Да, а вы что думали? /etc/fstab использует пробелы и переносы строк как разделители. Но что если имена папок содержат, скажем, пробелы? На этот случай формат fstab'а предусматривает специальное экранирование имён папок. Так что любой скрипт, читающий fstab, оказывается, должен это экранирование интерпретировать. Например, с помощью специально предназначенной для этого утилиты fstab-decode (запускать от рута). Не знали, да? Идите исправляйте свои скрипты :) В результате для каждого системного конфига нужен свой парсер. И было бы гораздо проще, если бы для системных конфигов использовался вместо этого какой-нибудь JSON или XML. А может быть даже некий бинарный формат. Особенно для тех конфигов, которые постоянно читаются разными программами. И для которых, как следствие, нужна хорошая скорость чтения (а у бинарных форматов она выше).

      Я не закончил по поводу «всё есть текст». Стандартные утилиты выдают вывод в виде простого текста. Для каждой утилиты фактически нужен свой парсер. Часто приходится парсить вывод той или иной утилиты при помощи sed, grep, awk и т. д. У каждой утилиты свои опции для того, чтобы установить, какие именно столбцы нужно выдавать, по каким столбцам нужно сортировать вывод и т. д. Было бы лучше, если бы утилиты выдавали вывод в виде XML, JSON, некоего бинарного формата или ещё чего-нибудь. А для удобного вывода этой информации на экран и для дальнейшей работы с ней можно было бы пайпить результат в дополнительные утилиты, которые убирают те или иные столбцы, сортируют по тому или иному столбцу, выбирают нужные строки и т. д. И либо выводят результат в виде красивой таблички на экран, либо передают его куда-то дальше. И всё это универсальным способом, не зависящим от исходной утилиты, которая сгенерировала вывод. И без необходимости парсить что-либо регексами. Да, UNIX shell плохо работает с JSON и XML. Но ведь у UNIX shell полно других недостатков. Нужно выкинуть его вовсе и заменить на некий другой язык, который помимо всего прочего может удобно работать со всякими JSON.

      Вы только представьте! Вот допустим, нужно удалить все файлы в текущей папке с размером, большим 1 килобайта. Да, я знаю, что такое надо делать find'ом. Но давайте предположим, что это нужно сделать непременно ls'ом (и без xargs). Как это сделать? Вот так: LC_ALL=C ls -l | while read -r MODE LINKS USER GROUP SIZE M D Y FILE; do if [ "$SIZE" -gt 1024 ]; then rm -- "$FILE"; fi; done. (LC_ALL здесь нужен был, чтобы быть уверенным, что дата будет занимать именно три слова в выводе ls). Мало того, что это решение выглядит некрасиво, оно ещё страдает рядом недостатков. Во-первых, оно не будет работать, если имя файла содержит перевод строки или начинается с пробела. Далее, нам нужно явно перечислить названия всех столбцов ls, ну или как минимум помнить, на каком месте находятся интересующие нас (т. е. SIZE и FILE). Если мы ошибёмся в порядке столбцов, то ошибка выяснится лишь на этапе выполнения. Когда мы удалим не те файлы :)

      А как бы выглядело решение в идеальном мире, который я предлагаю? Как-то так: ls | grep 'size > 1kb' | rm. Кратко, а главное смысл виден из кода, и невозможно ошибиться. Смотрите. ls в моём мире всегда выдаёт всю инфу. Специальная опция -l для этого не нужна. Если нужно убрать все столбцы и оставить только имя файла, то это делается специальной утилитой, в которую нужно направить вывод ls. Итак, ls выдаёт список файлов. В некоем структуированном виде, скажем, JSON. Это представление «знает» названия столбцов и их типы, т. е. что это, строка, число или что-то ещё. Далее этот вывод направляется в grep, который в моём мире выбирает нужные строки из этого JSON. JSON «знает» названия полей, поэтому grep «понимает», что здесь означает «size». Более того, JSON содержит инфу о типе поля size. Он содержит инфу о том, что это число, и даже что это не просто число, а размер файла. Поэтому можно сравнить его с 1kb. Далее grep направляет вывод в rm. rm «видит», что он получил файлы. Да, да, JSON ещё и хранит инфу о типе этих строк, о том, что это — файлы. И rm их удаляет. А ещё JSON отвечает за правильное экранирование специальных символов. Поэтому файлы со спецсимволами «просто работают». Круто? Идею я взял отсюда (там ещё есть ссылка на более подробный английский оригинал), посмотрите. Ещё замечу, что в Windows Powershell реализовано как раз что-то похожее на эту идею.

    • UNIX shell. Ещё одна базовая идея UNIX. Причём о мелких недостатках UNIX shell я уже поговорил в первой части статьи. Сейчас будут крупные. В чём «крутость» UNIX shell? В том, что на момент своего появления (это было очень давно) UNIX shell был гораздо мощнее командных интерпретаторов, встроенных в другие ОС. И позволял писать более мощные скрипты. Да и вообще, на момент своего появления UNIX shell был, видимо, самым мощным из скриптовых языков вообще. Потому что нормальных скриптовых языков, т. е. таких, которые бы позволяли полноценное программирование, а не только скриптинг, тогда, видимо, вообще не существовало. Это потом уже в один прекрасный день один программист по имени Larry Wall заметил, что UNIX shell всё-таки недостаёт до нормального языка программирования. И он захотел соединить краткость UNIX shell'а с возможностью полноценного программирования из C. И создал Perl. Да, Perl и другие последующие скриптовые языки программирования фактически заменили UNIX shell. Это константирует даже Роб Пайк, один из авторов (как я считаю) той самой «философии UNIX» (про него мы ещё поговорим). Вот здесь на вопрос об «одной утилите для одной вещи» он сказал: «Those days are dead and gone and the eulogy was delivered by Perl». Причём я считаю, что эта его фраза относилась к типичному использованию UNIX shell, т. е. к ситуации связывания большого количества маленьких утилит в shell-скрипте. Нет, говорит Пайк, просто используйте Perl.

      Я не закончил про UNIX shell. Рассмотрим ещё раз пример кода на shell, который я уже приводил: find foo -print0 | while IFS="" read -rd "" A; do touch -- "$A"; done. Здесь в цикле вызывается touch (да, я знаю, что этот код можно переписать на xargs, причём так, чтобы touch вызывался только один раз; но давайте пока забьём на это, хорошо?). В цикле вызывается touch! То есть для каждого файла будет запущен новый процесс! Это нереально неэффективно. Код на любом другом языке программирования будет работать быстрее этого. Просто на момент появления UNIX shell он был одним из немногих языков, которые позволяют написать это действие в одну строчку.

      Короче говоря, вместо UNIX shell нужно использовать любой другой скриптовый язык программирования. Который подходит не только для скриптинга, но и для реального программирования. Который не запускает новый процесс каждый раз, когда нужно «touch'нуть» файл. Возможно, понадобится «доложить» в этот скриптовый язык средства для простого выполнения вещей, которые есть в shell, скажем, для создания пайпов.

    • Простота. Здесь я говорю не конкретно про shell и про связывание кучи простых утилит из shell'а (про это был предыдущий пункт), а про простоту вообще. Использование простых инструментов. Скажем, редактирование картинки sed'ом. Да, да. Конвертим jpg в ppm при помощи командной строки. Затем при помощи текстового редактора, grep, sed и такой-то матери редактируем картинку. А потом обратно в jpg. Да, так можно. Но часто photoshop'ом или gimp'ом всё-таки лучше. Хоть это и большие, интегрированные программы. Не в стиле UNIX.

    На этом я закончу эти пункты. Да, хватит. Есть идеи в UNIX, которые мне реально нравятся. Скажем, «программа должна делать одну вещь и делать её хорошо». Но не в контексте shell. Вы уже поняли, что я не люблю shell. (Ещё раз повторю, я считаю, что в приведённом выше интервью Пайка он воспринял принцип «программа должна делать одну вещь и делать её хорошо» именно в контексте shell и потому отверг его). Нет, я говорю про этот принцип в своей сути. Скажем, консольный почтовый клиент не должен иметь встроенный текстовый редактор, он должен просто запустить некий внешний редактор. Или вот принцип, по которому нужно писать консольное ядро для программы и потом графическую оболочку для этого ядра.

    Теперь общая картина. Однажды появился UNIX. На момент появления он был прорывом. И он был во многом лучше своих конкурентов. UNIX имел много идей. И, как и любая ОС, UNIX требовал от программистов соблюдения некоторых принципов при написании прикладных программ. Идеи, лежащие в основе UNIX, стали называться «философией UNIX». Одним из тех людей, которые сформулировали философию UNIX, был уже упомянутый Роб Пайк. Он это сделал в своей презентации «UNIX Style, or cat -v Considered Harmful». После презентации он вместе с Керниганом опубликовал статью по мотивам презентации. В ней авторы рассказали о том, что, скажем, предназначение cat — это только конкатенация и ничего больше (ну то есть «склеивание» файлов, мы с вами помним, как расшифровывается cat, так ведь?). Возможно, что это Пайк как раз и придумал «философию UNIX». В честь этой презентации был назван сайт cat-v.org, почитайте его, очень интересный сайт.

    Но потом, через много лет, этот же Пайк сделал ещё две презентации, в которых, как я считаю, отменил свою философию обратно. Поняли, фанатики, да? Ваш кумир отказался от своей же философии. Можете расходиться по домам. В первой презентации «Systems Software Research is Irrelevant» Пайк сетует на то, что никто больше не пишет новых ОС. А даже если и пишут, то просто ещё один UNIX (который подразумевается в этой презентации уже чем-то неинтересным): «New operating systems today tend to be just ways of reimplementing Unix. If they have a novel architecture — and some do — the first thing to build is the Unix emulation layer. How can operating systems research be relevant when the resulting operating systems are all indistinguishable?»

    Вторую презентацию Пайк прямо называет: «The Good, the Bad, and the Ugly: The Unix Legacy». Пайк говорит, что простой текст не универсален, он хорош, но работает не всегда: «What makes the system good at what it's good at is also what makes it bad at what it's bad at. Its strengths are also its weaknesses. A simple example: flat text files. Amazing expressive power, huge convenience, but serious problems in pushing past a prototype level of performance or packaging. Compare the famous spell pipeline with an interactive spell-checker». Далее: «C hasn't changed much since the 1970s… And — let's face it — it's ugly». Дальше Пайк признаёт ограниченность пайпов, соединяющих простые утилиты, ограниченность регексов.

    UNIX был гениальным на момент своего появления. Особенно, если учесть, какие инструменты были в распоряжении у авторов UNIX. У них не было уже готового UNIX, чтобы на нём можно было разрабатывать UNIX. У них не было IDE. И программировали они вообще на ассемблере изначально. У них, видимо, был только ассемблер и текстовый редактор.

    Люди, стоящие у истоков UNIX, в определённый момент начали писать новую ОС: Plan 9. В том числе упомянутые Томпсон, Ритчи и Пайк. Учитывая многие ошибки UNIX. Но и Plan 9 никто не возводит в абсолют. В «Systems Software Research is Irrelevant» Пайк упоминает Plan 9, но несмотря на это всё равно призывает писать новые ОС.

    James Hague, ветеран программирования (занимается программированием с восьмидесятых) пишет: «What I was trying to get across is that if you romanticize Unix, if you view it as a thing of perfection, then you lose your ability to imagine better alternatives and become blind to potentially dramatic shifts in thinking» (ссылка). Прочитайте эту статью и его же статью «Free Your Technical Aesthetic from the 1970s», на которую он ссылается. (Вообще, если вам понравилась моя статья, то и его блог тоже, наверное, понравится, погуляйте там по ссылкам).

    Итак, я не хочу сказать, что UNIX — плохая система. Просто обращаю ваше внимание на то, что у неё есть полно недостатков, как и у других систем. И «философию UNIX» я не отменяю, просто обращаю внимание, что она не абсолют. Мой текст обращён скорее к фанатикам UNIX и GNU/Linux. Провокационный тон просто чтобы привлечь ваше внимание.

    UPD от 2017-02-14: комментаторы указывают, что сравнивать UNIX shell с PHP некорректно. Конечно, некорректно! Потому что UNIX shell не претендует на то, чтобы быть полноценным языком программирования, он предназначен для скриптинга системы. Вот только я в одно время этого не знал. И вдобавок считал UNIX shell прекрасным. Вот для людей в таком же положении я всё это и говорю. Ещё как минимум один комментатор говорит, что сравнивать UNIX shell нужно с cmd. Я бы сказал, что сравнивать надо с Windows Powershell. Последний, как я уже говорил, в чём-то превосходит UNIX shell.

    UPD от 2017-02-14: мне понравился вот этот коммент от sshikov:

    Но я скажу за автора — к сожалению, прямо сегодня можно найти сколько угодно восторженных статей типа «А вот есть такая замечательная фигня, как bash, щас я вам про нее расскажу...» — где unix way откровенно перехваливается неофитами. Это не помешает иногда компенсировать долей скепсиса.

    Да, в этом-то и всё дело! Достало, что хвалят UNIX way. Что считают UNIX красивым и ещё и других учат. А использовать-то UNIX можно.

    UPD от 2017-02-14: как минимум один комментатор сказал, что пересел с Windows на UNIX-подобные ОС и счастилив. Что поначалу он плевался от UNIX, но потом решил, что программировать под UNIX гораздо проще, чем под Windows. Так вот, я тоже сперва использовал и программировал на Windows. Потом пересел на UNIX. И сперва, конечно, было очень непривычно. Потом прочувствовал «философию UNIX», ощутил всю её мощь. Программировать под UNIX стало легко. Но позже пришло ещё одно озарение. Что UNIX неидеальна, а «философия UNIX» неабсолютна. Что программирование на «голом UNIX», с использованием C и Shell сильно уступает, скажем, Web-программированию. И далеко не только потому, что в Web-программировании используются языки, в которых трудно выстрелить себе в ногу, в отличие от C (тут языку C предъявить нечего, он намеренно является низкоуровневым). Но ещё и из-за всех этих quirks мейкфайлов, шела, языка C. Отсутствия удобных инструментов, систем сборки, менеджеров пакетов. Всё это, в принципе, можно было бы исправить. Вот я написал эту статью, чтобы открыть на это глаза тем, кто об этом не знает. У Windows тоже полно недостатков (я разве где-то говорил, что Windows лучше UNIX?). Но в чём-то Windows лучше UNIX (как минимум в некоторых особенностях Powershell). Сейчас я продолжаю использовать и программировать под UNIX. UNIX меня устраивает, мне достаточно удобно, хотя теперь уже я вижу многие его недостатки. Я не призываю бросать UNIX. Используйте UNIX дальше, просто не считайте его идеалом.

    UPD от 2017-02-15: habrahabr.ru/post/321652/#comment_10070776.

    UPD от 2017-02-15: habrahabr.ru/post/321652/#comment_10071096.

    UPD от 2017-02-15: habrahabr.ru/post/321652/#comment_10071714.

    UPD от 2017-02-16: понравился этот коммент: habrahabr.ru/post/321652/#comment_10066240.

    UPD от 2017-02-16: многие комментаторы рассказывают, как же полезны и удобны UNIX системы. Что они есть уже десятки лет, на них работает весь интернет. Что они стабильны и прекрасно справляются с возложенными на них задачами. И даже удалённо переустановить GNU/Linux можно :) А я и не спорю. Я не призываю отказываться от UNIX. Я просто хочу, чтобы вы видели недостатки UNIX. UNIX работает, используйте его. Процитирую James Hague, на которого я уже ссылался:

    Enough time has passed since the silly days of crazed Linux advocacy that I'm comfortable pointing out the three reasons Unix makes sense:

    1. It works.
    2. It's reliable.
    3. It stays constant.

    But don't--do not--ever, make the mistake of those benefits being a reason to use Unix as a basis for your technical or design aesthetic. Yes, there are some textbook cases where pipelining commands together is impressive, but that's a minor point. Yes, having a small tool for a specific job sometimes works, but it just as often doesn't.

    Одно время я тоже, как и многие из вас, повёлся на эту «философию UNIX». Думал, что она прекрасна. А потом понял, что это не так. И вот этим своим открытием я хочу с вами поделиться. Мои мысли не новы. Они уже есть в приведённых мною ссылках. Я просто хочу сообщить эти мысли аудитории Хабра. Мой пост написан наскоро, ночью. Читайте скорее не его, а ссылки, которые я привожу. В первую очередь две презентации Пайка, в которых он «отменяет философию UNIX» и два поста от James Hague. Мой пост фактически написан, чтобы привлечь внимание к этим ссылкам.

    Как минимум один из комментаторов сказал, что многие из названных мной «недостатков» UNIX недостатками не являются. Например, слишком короткие имена команд. Ну да. Это не недостаток. Но это пример необдуманного решения. Сиюминутного решения, принятого под влиянием обстоятельств, имевших важность тогда. Как и с тем примером с /usr или make. Я показываю, что UNIX была непродумана. Да и вообще, вглядитесь в историю UNIX! Сотрудникам Bell Labs не понравилась сложность проекта Multics. Они сказали: «Да ну этот Multics, давайте по-быстрому напишем свою ОС, запростецкую». И написали. Понимаете? ОС получилась довольно хорошей. Но не идеальной. UNIX — это хак. Успешный хак, который выполнил свою миссию и продолжает её выполнять.

    В комментариях была мысль, что заголовок поста не соответствует содержанию, и что я критикую не самую суть, философию UNIX, а просто привожу некий список недостатков. Возможно даже не всего класса UNIX-подобных систем, а конкретных реализаций. Так вот, это не так. Да, статья начинается с перечисления мелких недостатков. Этим я обращаю внимание на то, что в UNIX полно костылей, как и в других системах. В том числе очень старых, оставшихся во всех UNIX системах и попавших во все стандарты. Но я критикую и саму философию UNIX. Основные принципы (но не все!). Язык C, UNIX shell, идею конвееров, «всё есть текст». Замечу, что компилятор C и make, хоть и являются по идее отдельными программами, всегда рассматриваются как неотъемлемая часть экосистемы UNIX. И входят в POSIX. Некоторые комментаторы пишут: «А я сижу в IDE и не использую этот ваш make». Ну окей, хорошо, мой пост предназначен скорее как раз для тех фанатиков, которые считают, что всякие IDE — это не труъ и что программировать нужно непременно используя голый C, make и shell.

    И я не говорю, что философия UNIX (даже в тех местах, которые мне не нравятся) всегда не верна. Часто конвееры и shell-скрипты — это именно то, что нужно. Но не всегда.

    Некоторые комментаторы указывают, что голый shell, make и прочее часто скрыты от глаз юзера всякими обёртками, всякими IDE, сложными системами сборки, GUI-интерфейсами и пр. Ну да. Так ведь это и есть признак кривости системы :) Когда что-то уродское покрывают слоем красоты. А ещё абстракции протекают. А потому использовать, скажем, autotools ещё сложнее, чем голый make. Потому что чтобы использовать autotools, нужно знать ещё и m4, make и shell. Да, да, всю эту цепочку языков, используемых при генерации окончательного мейкфайла.

    Один комментатор приводит следующие принципы UNIX:

    Write programs that do one thing and do it well.
    Write programs to work together.
    Write programs to handle text streams, because that is a universal interface.

    С первыми двумя я согласен при условии, что они понимаются в отрыве от UNIX shell и конвееров. Их можно перенести даже на новомодные микросервисы, общающиеся с помощью REST. С третьим я не согласен (как я понимаю, подразумевается именно придумываение простого кастомного текстового формата для каждого случая вместо единого формата наподобие JSON). Часто текст — это именно то, что нужно. Но пихать его везде как universal interface глупо. На эту роль скорее претендует JSON или XML. Или, может, какой-нибудь формат для структуированных данных, который ещё не изобрели.

    Многие указали на искусственность некоторых примеров на shell. Ну да, я знаю, что их можно было бы переписать на find -exec или xargs. Ну что вы хотите, наскоро написанная статья. Можно было привести примеры получше, просто мне не хотелось. Это не отменяет того, что в shell'е постоянно возникают проблемы со специальными символами. Которые нужно по-особому обходить. И вообще у shell'а полно quirks, которые нужно постоянно держать в голове. И он запускает новые программы на каждый чих.

    Я вам ещё покушать принёс. Вот вам цитата от безусловно ещё одного вашего кумира Линуса Торвальдса:

    iTWire: Systemd seems to depart to a large extent from the original idea of simplicity that was a hallmark of UNIX systems. Would you agree? And is this a good or a bad thing?

    Linus Torvalds: So I think many of the «original ideals» of UNIX are these days more of a mindset issue than necessarily reflecting reality of the situation.

    There's still value in understanding the traditional UNIX «do one thing and do it well» model where many workflows can be done as a pipeline of simple tools each adding their own value, but let's face it, it's not how complex systems really work, and it's not how major applications have been working or been designed for a long time. It's a useful simplification, and it's still true at *some* level, but I think it's also clear that it doesn't really describe most of reality.

    It might describe some particular case, though, and I do think it's a useful teaching tool. People obviously still do those traditional pipelines of processes and file descriptors that UNIX is perhaps associated with, but there's a *lot* of cases where you have big complex unified systems.

    And systemd is in no way the piece that breaks with old UNIX legacy. Graphical applications seldom worked that way (there are certainly _echoes_ of it in things like «LyX», but I think it's the exception rather than the rule), and then there's obviously the traditional counter-example of GNU emacs, where it really was not about the «simple UNIX model», but a whole new big infrastructure thing. Like systemd.

    Now, I'm still old-fashioned enough that I like my log-files in text, not binary, so I think sometimes systemd hasn't necessarily had the best of taste, but hey, details…


    UPD от 2017-02-18: ещё по поводу надуманных примеров на shell. Вы говорите, примеры надуманные, что можно сделать find -exec или xargs. Да, можно. Но как минимум сам факт того, что нужно постоянно держать в голове, что, мол, цикл нельзя и нужен -exec и xargs — это уже костыль. Проистекающий из принципа «всё есть текст», ну или из слишком тупой реализации этого принципа в UNIX shell.

    Итак, сейчас я приведу такую задачу, в которой любое решение будет уродским, даже с использованием find -exec и xargs.

    Вернёмся к моему примеру с touch'ем. «Как touch'нуть все файлы в папке foo (и во вложенных)?» Допустим, что нужно не touch'нуть их, а grep'нуть из них все строки со словом bar и положить результат туда же. Т. е. для каждого файла file сделать grep bar file > tmp; mv tmp file. Как быть? Если делать решение с циклом, то мы упираемся в те пять хаков, которые нужно сделать, чтобы не выстрелить себе в ногу. Результат будет таким, со всеми пятью хаками:

    find foo -print0 | while IFS="" read -rd "" A; do
    	grep -- bar "$A" > tmp
    	mv -- tmp "$A"
    done
    

    Ладно, хорошо, мы знаем, что имя файла начинается на foo, а потому не может начинаться с дефиса и пробела. Но оно может заканчиваться на пробел, а потому тот трюк с IFS всё равно нужен. Так что единственный хак, от которого можно избавиться, зная, что имя начинается с foo — это написание --. Но даже от этого хака я бы не советовал избавляться, т. к. постоянное использование -- даёт понять читающему: «Да, я подумал об этом». Это как условия Йоды.

    Окей, можно ли этот пример написать проще с использованием xargs или find -exec? Если бы каждый файл нужно было всего лишь touch'нуть, то да, можно было бы написать существенно проще. Но если нужно выполнить два действия: grep и переименование, то существенного упрощения мы уже не получим. Два действия означают, что нам уже нужно запихивать эти два действия в вызов shell'а, в sh -c. Как будет выглядеть результат? Может быть, так?

    find foo -exec sh -c "grep -- bar '{}' > tmp; mv -- tmp '{}'" ';'
    

    Нет, неправильно! Это не будет работать, если имя содержит одинарную кавычку. Правильный вариант таков:

    find foo -exec sh -c 'grep -- bar "$1" > tmp; mv -- tmp "$1"' dummy '{}' ';'
    

    Видите? Опять хак. Нам пришлось передать имя файла через $1. И по-прежнему нужно помнить, что нам нужны двойные кавычки вокруг $1. То же самое было бы с xargs. Опять нужен sh -c и опять нужно передавать аргументы через $1.

    Всё это сделать можно, если надо, но сам факт того, что нужно постоянно держать это в голове и обходить грабли, говорит о том, что здесь что-то не то.

    Теперь по поводу другого примера. Где нужно удалить все файлы определённого размера. Да, всё это можно сделать одним вызовом find. Там есть опции и для проверки размера, и для удаления. Да. Вот только я вижу здесь хак. Хак в том, что find имеет фактически в себе целый sublanguage, подъязык. Язык вот этих вот опций. Почитайте хорошенько ман find'а. Вы узнаете, что, оказывается, порядок опций find'а имеет значение. Что каждая опция имеет truth value, т. е. булевское значение. Что можно по-хитрому комбинировать эти опции. Что в зависимости от порядка опции, от их truth value find принимает решение, в какой момент нужно остановить обработку опций для данного файла и нужно ли descend в данный каталог (т. е. нужно ли искать внутри этого этого каталога).

    Я помню, как однажды жутко оплошался, не зная этих тонкостей. Я набрал find -delete -name '*~' вместо find -name '*~' -delete или что-то такое. Ну подумаешь, думал я, опции не в том порядке. Смысл же тот же. И find удалил всё. Снёс мои важные файлы. Потом я восстановил из бекапа, так что всё ок. Это потом уже я понял, что -name имеет truth value true в случае, если файл соответствует маске. И если -name вернул true, то обработка опций продолжается.

    Что тут плохого? Плохо то, что find имеет свой sublanguage. Что это ещё один язык в дополнение к shell. (А sed, кстати говоря — это ещё один язык, а awk — это ещё один язык и так далее, авторы UNIX'а любили создавать по языку на каждый чих.) Нужно было вместо этого сделать так, чтобы find только умел искать файлы. А всю остальную функциональность нужно вынести из него. Проверки на размер файла должны быть снаружи. А если find'у нужно принять решение, нужно ли descend в данный каталог, то он должен вызывать внешний callback. Да, в UNIX shell так вряд ли получится. На то он и UNIX shell.

    UPD от 2017-08-01.

    echo вроде как предназначен, чтобы печатать на экран строки. Вот только использовать его для этой цели, если строчка чуть сложнее, чем «Hello, world!», нельзя.

    И даже для этой цели echo использовать можно не всегда. Недавно прочитал, что в интерактивном старом bash нельзя писать echo "Hello, world!". Вот несколько абзацев текста, объясняющих суть проблемы и пути обхода. В новых bash такого нет, на моей системе не воспроизводится.
    Поделиться публикацией
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама
    Комментарии 699
    • +161
      «Статья написана наскоро, «полировать» дальше не хочу, скажите спасибо, что написал.»
      Охренеть, одолжение сделал :)
      • –21
        Дюже странно, что карму еще не слили. Ну, хабр- он такой…
        • 0
          Уже слили, не волнуйтесь
          • –2
            Ну, мне-то и сливать было нечего, но мир не без добрых людей- спасибо за минусы
            • –2
              кто-то оголтело лепит минус просто потому что сказанное идет вразрез с его убеждениями, а кто-то ставит плюс к статье за то что в ней есть котик. Скоро котировки валют на месяц вперед будет проще предсказать чем собственную карму/рейтинг на хабре.
        • +74
          это ж сарказм, замешанный на философии UNIX
          • +8
            Зашел в профиль посмотреть другие посты автора. Опа!

        • –16
          Да, всё так. Я бы ещё проехался по любимому языку юниксоидов — голым сям, Уже лет 20 нет ни одной причины не использовать вместо него си с плюсами, даже для системных вещей, тем более что в с-стиле можно и на плюсах прекрасно писать.
          А вообще проблема не в юникс, не в прочих ос или инструментах, проблема в людях. Из любой достаточно долгоживущей и сложной системы, над которой работает масса людей, по факту получается свой клубок костылей с велосипедами, можно даже никакие статьи с критикой не читать. Панацеи тут быть не может, поэтому просто надо набираться опыта и самому делать хорошо. Получится не сразу, а когда начнет получаться, будет уже поздно. Выхода нет, смиритесь.
          • –4
            На работе всегда говорю, «ошибки не в людях, а в сервисах». Люди не ошибаются, они делают не всегда то что от них кому-то хочется. А вот сервисы уже предназначены для того, чтобы делать то, что хочется его владельцу, поэтому если делают не то — ошибаются.
            • +3
              Проблема в том что для системного программирования кроме С и С++ пока к сожалению ничего нет (ну вот появился Rust но он еще мало распространен… да и с синтаксисом некоторые вопросы к интуитивности, в тех же же C# или Java все гораздо более понятно, причем сходу, без необходимости погружаться в нюансы языка).
              • –6
                Ну так большая разница же, с и с++, я про что и пытался сказать. С++ рулит, в отличие от.
                • +13

                  C++ — это такой ужасный монстр. И иногда вместо C++ нужно использовать C. Чтобы вместо вот этого монстра использовать монстрика поменьше

                  • 0
                    Настоящая причина использовать Си вместо С++ в 90% случаев куда тривиальнее: отсутствие компилятора С++ для конкретного устройства. Никто же не заставляет использовать все эти «монструозные» вещи типа буста, можно даже писать большую часть кода на общем подмножестве.
                    • +5
                      Монстры только у людей в головах. Ничего же не мешает вам писать на ++ в стиле си и аккуратно использовать некоторые полезные плюшки, тот же RAII, но без фанатизма, без буста, без лямбд.
                      А вот в голом си приходится изголяться, дефайны, goto, MyObject_DoSomething(MyObject* self) и прочие радости.
                      • 0

                        Я считаю, у C++ нет самодостаточных подмножеств, не считая самого C++, разумеется (C, к сожалению, не является подмножеством C++). Попытка выделить некоторое подмножество C++ для своего проекта обречена на провал. Вот допустим, есть проект "в стиле C" для UNIX, я хочу заюзать в нём RAII для файловых дескрипторов (fd). Окей, написал свой объект-обёртку для fd. Потом выясняется, что нужно либо запретить копирование для этого объекта, либо реализовать в конструкторе копирования dup. И не зависимо от выбранного варианта нам нужно уметь возвращать наш объект из функции, а для этого уже нужен конструктор перемещения, а это уже C++11. Ну и так далее, так постепенно вы притянете весь C++ во всей своей красе.


                        When you’re programming C++ no one can ever agree on which ten percent of the language is safe to use. There’s going to be one guy who decides, “I have to use templates.” And then you discover that there are no two compilers that implement templates the same way

                        https://gigamonkeys.wordpress.com/2009/10/16/coders-c-plus-plus

                        • +3
                          Потом выясняется, что нужно либо запретить копирование для этого объекта, либо реализовать в конструкторе копирования dup. И не зависимо от выбранного варианта нам нужно уметь возвращать наш объект из функции, а для этого уже нужен конструктор перемещения, а это уже C++11

                          Ох уж эта аргументация. Ну напишете вы около 8 строчек кода, не облысеете. Зато потом не придется перебирать все точки возврата из всех функций работающих с файлом, все обработчики ошибок и т.д. чтобы нигде не забыть закрыть этот хендлер.

                          https://gigamonkeys.wordpress.com/2009/10/16/coders-c-plus-plus

                          напомнило
                    • +3
                      Я раза 3-4 порывался перейти с C на C++, даже в некоторых больших проектах на плюсах принимал участие, но не прёт меня от них, всегда возвращался к голому C. Единственное, чего мне не хватает на «голом» по сравнению с плюсами — это libslave (скоро допишу свою на сях), нормальной библиотеки под протобуф и RapidJSON (тоже можно пережить).

                      Голый C прекрасен, просто он не всем подходит.
                      • +3

                        Так это про любой язык можно сказать, что он прекрасен, просто не всем подходит.

                        • +4
                          BF вообще замечательный, его лаконичность потрясает. А если вам не нравится, то вы просто школотроны, единственно на что способные — кнопки по формам расставлять. Fixed for ya.
                          • –1
                            Именно! Все языки по-своему прекрасны и у каждого найдутся приверженцы.
                    • +13
                      Уже лет 20 нет ни одной причины не использовать вместо него си с плюсами, даже для системных вещей, тем более что в с-стиле можно и на плюсах прекрасно писать.

                      Есть. libstdc++ во флешу не пролазит. Толстая слишком.

                      • –23
                        А вот эта вся экономия на копеечных флэшах она как правило боком выходит рано или поздно. Должен быть запас минимум в 2 раза, если планируется хоть какое-то минимальное развитие продукта. У нас тоже в свое время в одном из продуктов лет 12 назад наэкономили, поставили 4ГБ, и рамки впритык. Потом через 2-3 года сразу в 8 раз запас сделали, экономия сильно убыточная вышла по факту.
                        • +41
                          4ГБ

                          У нас 32КБ

                          • +4

                            На attiny младших ещё меньше, и ничего, на плюсах писать вполне можно. Без экзепшонов и rtti, конечно, но плюсы ими не ограничиваются.

                            • 0

                              Ну я их в итоге завёл там без стандартной библиотеки путём выключения лишнего во флагах компиляции и написанием заглушек под хлам типа __verbose_terminate_handler. Что не отменяет упитанности libstdc++.

                          • +2
                            А вы вкурсе, что есть ОС (стоит отметить, *nix ОС) под всякие встраиваемые системы и МК? Там такая память только в очень сладких снах может сниться.
                            • –3
                              Я где-то говорил что предлагаю всем 4 гига ставить? Это пример был, из личного опыта. Если у Вас 32 КБ (это наверное что-то космическое суперотказоустойчивое), то можно взять запас до 64 КБ, да в конце концов, из любого правила есть и исключения, пишите в этом случае на си, на здоровье, не надо же все советы так буквально воспринимать, а то я смотрю народ прям переволновался. Под 32 кб можно и на асме написать.
                              • 0
                                можно взять запас до 64 КБ

                                У меня не получалось упихнуть libstdc++ и в 64 кб. Говорю же, толстая слишком. А без неё запас неплохой есть, да.

                          • +1
                            Так не нужно использовать std от C++. Это чудовищное поделие. Там из полезного только exceptions, но я думаю их как-нить можно вынуть оттуда, не таща с собой весь остальной хлам.
                            А сам С++ с RAII и остальным весьма крут, хотя сильно больше нюансов, чем в голом С.
                            • –3
                              <сарказм>
                              Не оскорбляйте святое. Люди привыкли писать на голом С, это развивает внимательность, аккуратность. Сделал, как говорится, fopen, не забудь про fclose, да и код получается длинный, солидный. А все эти ваши гейские RAII — не нужны и не влазят в 8 кБ памяти, особенно если boost весь ещё заинклюдить.
                              </сарказм>
                              • –1
                                Механизм исключений без RAII бесполезен. Плюс, очень удивительно, что вы выделяете самую запрещаемую в проектах фичу языка как его основное преимущество
                                • +1
                                  Ну так я и говорю, что нужно RAII + exceptions. Но их реализация находится в райтайме С++. Хз кем и где она запрещена. Везде, где писал на С++ все использовали исключения и RAII как самое базовое, что С++ предоставляет по сравнению с голым С.
                                  То, что это в публичном стайлайде гугла написано, так это сильно не так внутри и сильно зависит от команд и наличия легаси кода. А изначально это пошло из-за плохой реализации исключений в старых компилярах с точки зрения производительности.
                                  • +2
                                    То, что это в публичном стайлайде гугла написано, так это сильно не так внутри и сильно зависит от команд и наличия легаси кода

                                    Вот что написано в публичном стайлгайде гугла.


                                    On their face, the benefits of using exceptions outweigh the costs, especially in new projects.
                                    • +1
                                      А изначально это пошло из-за плохой реализации исключений в старых компилярах с точки зрения производительности.

                                      никогда не понимал и не пойму, какая разница, насколько шустро отрабатывается исключительная ситуация
                                      • 0

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

                                        • 0
                                          Какие, нафиг, слухи? SJLJ — это единственное что работает на всяких хитрых, нестандартных, платформах (типа тех же микроконтроллеров), а dwarf2 — очень и очень жирный (что может быть, опять-таки, большой проблемой для микроконтроллеров).

                                          Вот тут подробнее.
                                        • 0
                                          Верно, но старая реализация исключений просаживала производительность просто от куска try-catch. То есть даже той ветви, которая успешная.
                                          На хабре где-то было про реализацию исключений статья.
                                          • 0
                                            В нынешний век интерпретаторов и П-кода это не то чтобы просадка, это погрешность измерений =)

                                            Там расходы были — пяток лишних ассемблерных инструкций.
                                          • 0
                                            Нет, ну overhead есть даже если нет исключений. Скажем, в Windows надо для каждого try, в том числе скрытого, создать элемент SEH, а в конце — удалить его. Да, это мизер.
                                    • 0
                                      -static-libstdc++ не отрабатывает?
                                      • +1
                                        libstdc++ во флешу не пролазит. Толстая слишком.
                                        Давно, если честно, не смотрел, но были же проекты uclibc++ и подобные, все умерли?
                                    • +43
                                      И эти файлы надо заново читать и заново парсить при каждом вызове ls -l! Было бы гораздо лучше использовать бинарный формат. Или БД. Или некий аналог реестра. Как минимум для вот таких вот критичных для производительности ОС файлов.

                                      Не стоит недооценивать производительность текстовых файлов.
                                      Собственно, какая вам разница, будет ли конец строки обозначать символ \0 или символ \n?
                                      SQLite/Berkley или на таких размерах проиграют по производительности.

                                      Полагаю, что чтение и парсинг /etc/passwords выиграет по скорости у чтения из реестра на порядки. Но это все в целом не важно, потому что роль идет даже не о миллисекундах — я набросал простенький скрипт на perl, он с парсит /etc/passwd с помощью регулярного выражения 100 тысяч раз за ~3s.

                                      printf внезапно является далеко не самым быстрым способ вывода информации на экран или в файл

                                      Форматируемый вывод оказывается не самый быстрый вывод! Я прямо-таки потрясен этим откровением. А нет, не потрясен. Это все написано в любой книге по С.
                                      • +2
                                        Собственно, какая вам разница, будет ли конец строки обозначать символ \0 или символ \n?

                                        Скорее, в случае с БД, она ничем заканчиваться не будет, будет указан её размер.
                                        /etc/passwords маленький файл для примера. А вот с большим файлом, со сложным форматом (вложенные секции, например), выигрыш будет на стороне БД. Файл не надо будет разбирать на строки, и эти строки парсить в дерево.
                                        • 0
                                          Скорее, в случае с БД, она ничем заканчиваться не будет, будет указан её размер.

                                          В postgresql, например, безразмерные строки будут незначительно быстрее строк с фиксированным размером.

                                          • +1

                                            Вы путаете "fixed size strings" и "pascal strings".
                                            "Безразмерные" строки в postrgesql как раз паскалевские и хранят свой размер (каламбур).

                                        • +2
                                          Предполагается что у баз данных есть индексы и самое главное контроль целостности до записи(имеется в виду завершение транзакции), чего нет у идеологии 'все есть текст', т.е. в случае с /etc/passd об ошибке скорее всего узнаем по факту использования.
                                          • +4
                                            Форматируемый вывод оказывается не самый быстрый вывод!

                                            Дело не в этом, а в том, что строка формата разбирается каждый раз во время выполнения.


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

                                          • –1
                                            Форматируемый вывод оказывается не самый быстрый вывод! Я прямо-таки потрясен этим откровением. А нет, не потрясен. Это все написано в любой книге по С.

                                            Окей, может быть вы это уже знали. А я это в своё время не знал. Я и подумать не мог, что, оказывается, вот этот вот дефолтный момент в C неэффективен. Я думал, что не могли же умные дядьки ошибиться и какую-то ерунду мне подсунуть. Естественно, в какой-то момент я начал догадываться, что форматный вывод неэффективен. Но опять-таки, я подумал, что раз C делали умные дядьки, то, видимо, он не до такой степени медленный. Но нет, как я выяснил от автора H20, форматный вывод таки существенно медленнее неформатного. Ну вот я сейчас этим откровением с Хабром делюсь.


                                            Вдобавок, во многих реализациях стандартной библиотеки C++ (как минимум до недавнего времени) потоки ввода-вывода были реализованы поверх форматных функций C! (Facepalm!) То есть в API C++ строк формата уже нет, внутри всё можно реализовать без них. Но эти идиоты всё равно внутри пихают форматные строки. Чтоб медленнее было. Я-то думал, что программисты умные. Что реализуют всё всегда как надо. Как бы не так! Есть ли этот баг по-прежнему в основных реализациях стандартной библиотеки C++, я не знаю. Вполне мог остаться

                                            • 0

                                              Там, где мне, наверное, единожды за последние года три это было важно, istream был быстрее scanf.


                                              Ну а самым быстрым вариантом был mmap + парсер на boost::spirit + boost::string_view. Но это так, заодно к слову о монстрах C++ vs C.

                                            • +18
                                              Особенно умиляет твердокаменная уверенность в том, что при крахе системы у бинарной конфигурации больше шансов выжить, чем у текстовой.
                                              Оставляя за скобками такой важный нюанс, что текстовую конфигурацию, при повреждении, куда легче и быстрее восстановить вручную, чем бинарную без дополнительного специфического инструментария
                                              • –7
                                                Бинарные сами следят за своей целостностью. Убить реестр внезапным ребутом почти не реально.
                                                • +5
                                                  юзеры ещё не то могут убить… Приходилось чинить. Там не все в двух копиях, вообще-то.
                                                  • 0
                                                    Согласен — начиная с 7ки, угрохать регистр падением системы стало практически невозможно. До этого — сколько угодно.
                                                    Тем не менее — если регистр повреждён (да даже действиями пользователя) до степени незагужаемости системы, это требует специфических инструментов для ремонта, в отличии от текстовых конфигов.
                                                    С точки зрения производительности системы, можно хранить в памяти результат чтения текстовых конфигов и обращаться к нему (рано или поздно вся эта концепция systemd к такому и приведёт).
                                                    • 0
                                                      Согласен — начиная с 7ки, угрохать регистр падением системы стало практически невозможно.

                                                      Отключение питания на этапе загрузки убивает реестр и на 7. Никогда не понимал логики, зачем надо писать в реестр до логина пользователя.
                                                      • 0
                                                        На каком? Как минимум до этапа chkdsk ОС точно ничего на диск не пишет.
                                                        • 0
                                                          На каком?

                                                          Где-то в районе анимированного бут-лого или сразу за ним.
                                                          • 0

                                                            У меня есть многострадальный комп, которым мне лень заниматься. Для кино и всякого. У него что-то с железом, что он часто ресетится. Иногда не включается. Но проводом подергал и завелось. Пару раз вис и не загружалась винда из за одного диска. Я его и сам не жалею. Долго выключается — ресет, долго думает — ресет, долго не включается — ресет. Винде по барабану. Живет не тужится.

                                                            • 0
                                                              Долго выключается — ресет, долго думает — ресет, долго не включается — ресет

                                                              В вашем опыте ключевое слово «долго», т.е. весь io уже закончился.
                                                              В моём опыте, всё внезапно и с железом всё нормально — старт системы, потеря питания, «убитый» реестр.

                                                              Показательно, что это не единичные случаи, несколько раз восстанавливал юзерские, когда в нервах ресет жмут на загрузке. И у себя словил 2 раза, чистой воды невезение, один раз аккум ноута в 0 ушёл на загрузке, второй раз электросети «уронили» десктоп.
                                                            • 0
                                                              Это ооооооочень пространное указание точки времени. Там мягко говоря много всего в этот момент происходит.
                                                              • 0
                                                                Суть то одна, пропадание питания в этот момент и как результат битый software.
                                                                • 0
                                                                  В чём проблема воспользоваться резервной копией? По-умолчанию в винде включены опции по созданию точек восстановления и копий реестра…
                                                                  • 0
                                                                    Которые умельцы сроду отключают и жалуются, что глючную винду приходится переустанавливать после каждого чиха.
                                                          • 0
                                                            Ну как зачем — процесс сверки обнаруженных устройств с существующими с last known good, например, или ещё какое-нибудь вуду. Регистр — он не для пользователя, по большому счёту, точнее у пользователя есть свой кусочек, в профиле, куда и начнут писАть, после того как он залогинится.
                                                            Я уже было решился спросить у человека какие именно технические детали позволяют ему с таким апломбом утверждать о самовосстановлении регистра (а вдруг?), а тут вы пришли и… разрушили мою веру в светлое бинарное завтра юникс-систем.
                                                            • 0
                                                              Ну как зачем — процесс сверки обнаруженных устройств с существующими с last known good

                                                              Запись там идёт только после успешного логина + задержка, что и свидетельствует об успешной загрузке.
                                                              Я уже было решился спросить у человека какие именно технические детали позволяют ему с таким апломбом утверждать о самовосстановлении регистра

                                                              Зачем восстанавливать то, то не упало? Механизмы записи в реестр сделаны для поддерживания его консистентного состояния при обрыве записи, а транзакционные механизмы NTFS не дают сработать и им.
                                                            • 0
                                                              BCD хранит свои конфиги в кусте реестра. Хотя правда не в курсе, он только читает или ещё и пишет?
                                                            • –3
                                                              До этого — сколько угодно.

                                                              Не соглашусь. На своей XP я никогда не видел разрушение реестра. Хотя и вырубал и во время загрузки, и во время выключения.
                                                              • +2
                                                                На вкус и на цвет все фломастеры разные — может у вас контроллер диска какой дружелюбный. То, что молния никогда в вас не попадала, вовсе не значит, что она не попадала в других людей.
                                                                • 0
                                                                  Я использовал весьма разное оборудование. Видимо, я везунчик.
                                                                  • 0

                                                                    Возможно дело в том, что раньше можно было ставить систему на FAT32 раздел со всеми вытекающими ;-)

                                                                    • 0
                                                                      на NTFS оно точно также в капусту билось, но как правило очень невоспроизводимо. какой-нить race condition при записи в глубине дискового стека, совпадающий с зависанием/вырубанием системы.
                                                                • +1
                                                                  Аналогично. Сколько ни отрубай «жестко». Ни на XP, ни на 2к.
                                                          • 0
                                                            А зачем там регулярка, там же фиксированный набор полей? Тот же GAWK в таких случаях (простые текстовые файлы с фиксированным набором полей) вообще рвет всех. Причем даже на гигабайтных простынях данных.
                                                          • +30
                                                            Про существование зомби-процессов все говорят: «It's for design».

                                                            Зомби-процесс — это завершенный дочерний процесс, который не «похоронен» родителем — по сути, от процесса остается минимальная запись в таблице процессов, содержимое буферов обмена и код завершения.

                                                            Обычном kill'ом зомби не убиваются

                                                            Убиваются, конечно же, только целиться надо в родителя. Пример: kill $(ps -A -ostat,ppid | awk '/[zZ]/{print $2}')

                                                            Долгие и пространные рассуждения про shell забавны в своей надуманности, но хотелось бы отметить, что сравнивать его возможности надо не с возможностями php, а с возможностями cmd.
                                                            • +3
                                                              А если родитель еще нужен?
                                                              • +1
                                                                Если есть зомби, то с родителем не всё в порядке, т.е. он уже не нужен.
                                                                • +8
                                                                  А если там критичные данные? Например ваша зарплата за год.
                                                                  • –7
                                                                    Вы сейчас о чём говорите, какие критичные данные, какая зп?

                                                                    Если есть зомби, то скорее всего родителя уже нет. Просто нет. Нет, от слова совсем. Со всеми данными.
                                                                    • +4
                                                                      Все понятно. В следующий раз рекомендую высказываться на тему в которой хоть немного разбираетесь.
                                                                      • +8
                                                                        Если есть зомби, то скорее всего родителя уже нет. Просто нет. Нет, от слова совсем. Со всеми данными.

                                                                        Зомби-процесс — это дочерний процесс, родитель которого не удосужился получить код завершения через wait. Если родитель умирает, то зомби наследуется init, который его без сожалений убивает.


                                                                        То есть, наличие зомби говорит о том, что родитель как раз есть. Другое дело, что в нём баг, но процесс есть.


                                                                        Не понимаю, за что заминусовали tgz.

                                                                        • +1
                                                                          Не в качестве несогласия с вашим комментарием, а как небольшая поправка. Когда родитель умирает дочерний процесс определенно наследуется каким-то другим процессом, но это совсем не обязательно именно init.
                                                                          • 0

                                                                            Да, согласен. Просто осиротевшего зомби в *NIX усыновляет процесс с PID=1, а его по инерции часто init называют. Хотя, конечно, всё может быть и по-другому.

                                                                            • +7
                                                                              Опять же не совсем верно. Кто наследует дочерний процесс после смерти родителя «implementation defined», т. е. это не обязательно init или процесс с pid=1. Более того в linux вообще может быть несколько процессов, которые собирают осиротевших детей (смотрите man prctl ту часть где описывается PR_SET_CHILD_SUBREAPER).
                                                                              • +2

                                                                                Ага, спасибо! Просто у Стивенса и Раго именно про PID=1 написано. Ну, теперь буду знать. :)

                                                                            • 0
                                                                              Sic!
                                                                              • 0

                                                                                Это как-то подтверждает ваши слова, что наличие зомби свидетельствует о смерти родителя? Или что вы хотели сказать?

                                                                                • –1
                                                                                  Или что вы хотели сказать?


                                                                                  К сожалению я не могу голосовать за комментарии, приходится выделять тот, который поддерживаю так как могу.

                                                                                  Зомби жив, пока родитель через wait состояние не получит. Единственное разумное, почему родитель этого не делает (я не беру в расчет отсутствие в коде этой возможности) — родителя уже нет или он не в состоянии нормально работать.
                                                                                  • +4

                                                                                    Вы недооцениваете вероятность наличия багов. :)

                                                                                    • 0
                                                                                      А если у родителя просто нужный тред заблокировался на IO, а все остальное хорошо и в порядке?
                                                                              • –1
                                                                                Просто хипстеры не умеют так:
                                                                                29755 pts/0 Ss 0:01 \_ /bin/zsh
                                                                                6123 pts/0 S+ 0:00 | \_ ./zombie
                                                                                6124 pts/0 Z+ 0:00 | \_ [zombie]

                                                                                [some magic]

                                                                                29755 pts/0 Ss 0:01 \_ /bin/zsh
                                                                                6123 pts/0 S+ 0:00 | \_ ./zombie


                                                                                И зомби умер. Без убивания папы.
                                                                                • +22
                                                                                  Я один вижу в этом ASCII-арте длинные грейдеры, убирающие снег?
                                                                            • +1
                                                                              А если RAM сдохнет? Или контроллер? Или питание вырубится?

                                                                              Если ваша зарплата за год имеется только в оперативной памяти одного сервера, валить надо из такой конторы.
                                                                              • +1
                                                                                Следуя этой логике можно сделать rm -rf /, а объяснить все тем, что мог ведь и контроллер сдохнуть. В маразм не впадайте. Ваша зарплата зависит от ваших действий, а не от того что лежит в памяти конкретного сервера.
                                                                                • 0
                                                                                  Нет, следуя этой логике, нельзя сделать rm, потому что логика в том, чтобы не хранить критически важные данные только в оперативной памяти одного процесса на одном сервере.
                                                                                  • 0
                                                                                    Маразм все же побеждает. Перечитайте изначальный пост, вопрос был не про зарплату. По существу есть что сказать?
                                                                                • +1
                                                                                  да что вы обычная черная бухгалтерия… все на RAM диске и бекап в крипте в облако в Зимбабве…
                                                                            • +4
                                                                              Если родитель нужен, то вполне может быть, что этому родителю нужна информация о том, как скончался его ребенок (код возврата, короче), так что какую-то информацию о завершившемся процессе все равно придется сохранть. Zombie процесс — просто способ сохранить эту информацию до тех пор, пока ее не запросит родитель.

                                                                              Но если вам это не нужно, то вы можете просто поправить обработчик SIGCHLD и вот вам автоматическая сборка этих Zombie. Это всего одна строка кода, так что не супер тяжелая задача.
                                                                              • –2
                                                                                Как вставить 1 строчку кода в уже запущенный бинарник?
                                                                                • +3
                                                                                  Если процесс не собирает своих детей, то значит они ему нужны и значит Zombie процессы должны быть, либо это просто недосмотр со стороны программиста(ов), который написали программу. Странно винить Unix за недосмотр программистов.
                                                                                  • –2
                                                                                    Где я винил unix?
                                                                                    • +1
                                                                                      Ок нигде. Тогда что к обсуждению должен был добавить ваш вопрос про то, как вставить 1 строчку кода в уже запущенный бинарник?
                                                                                      • 0
                                                                                        Наверно понимание того что вставить строчку нельзя по условию задачи.
                                                                                        • 0
                                                                                          Какой задачи? Избавиться от zombie? Так вроде как я вам выше объяснил, что zombie либо может быть нужен родителю и от него не нужно избавляться, либо родитель содержит ошибку — и это уже совсем другая история, исправлять ошибку в программе позволяя небезопасное действие странно.
                                                                                          • 0
                                                                                            А если зомби не нужен?
                                                                                            Вот прямо сейчас на ноуте:
                                                                                            20157 ? Ssl 0:09 gvim
                                                                                            20163 ? Z 0:00 \_ [python3]
                                                                                            Зомби мне не нужен, а vim содержит несохраненные данные.
                                                                                            • +4
                                                                                              Операционная система не знает ничего о логике приложения, она просто не может узнать, что zombie больше не нужен. Zombie будет удален тогда, когда гарантированно известно, что он не нужен и не раньше.

                                                                                              Если программа порождает дочерние процессы и не собирает их, хотя они ей не нужны — это бага в программе. Ее нужно фиксить в программе.
                                                                                              • 0
                                                                                                Ну так кроме ОС у нас еще есть админ. А у админа есть некоторые инструменты.
                                                                                                • +2
                                                                                                  То что админ есть, не значит, что ОС должна разрешать потенциально небезопасные действия (а убийство дочернего процесса, без разрешения родительского процесса — потенциально опасное действие, потому что логика родительского процесса может быть к этому не готова). Давайте все программы будут лазить друг к другу в память — админ же есть, он всех хулиганов накажет.
                                                                                                  • 0
                                                                                                    kill -9 потенциально небезопасен, но ОС же позволяет это делать, не так ли?
                                                                                                    • 0
                                                                                                      Так, а еще kill позволяет избавиться от zombie убив родителя, не так ли? И если родитель не собирает своих детей, хотя должен — то убивать нужно именно его, а не уже мертвый процесс, который ни в чем не виноват. Но как и всегда с kill -9 вы делаете это на свой страх и риск и не жалутесь на то, что в приложении могут быть несохраненные данные. Так что строго говоря, у администратора, который сам себе придумывает несуществующую проблему zombie процессов, все таки есть средство, чтобы с ними побороться.
                                                                                                      • 0
                                                                                                        Средство есть, только это совсем не kill -9 для папы.
                                                                                                        • 0

                                                                                                          То есть вы утверждает, что где-то в стандарте posix описывается способ удаления zombie, который не сводится к вызову wait со стороны процесса родителя и гарантированно работает? Поделитесь выдержкой из Posix или SUS.

                                                                                                          • –2
                                                                                                            А с чего это должно быть написано в стандарте? У вас есть стандарт как ложку ко рту подносить? Нет? А кушаете как?
                                                                                                            kill -9 ppid в посиксе описан?
                                                                                                            • +1
                                                                                                              У вас такая бурная реакция на все стандарты или только на те, что вам не нравятся? Касательно вашего вопроса, нет у меня нет стандарта как подносить ложку ко рту, но ложку ко рту я подношу себе сам, а не прошу это делать за меня какого-нибудь дядю. С другой стороны еда, которую я покупаю в магазине чтобы есть, стандартам соответствовать должна — потому как я не делаю ее сам.

                                                                                                              Но возвращаясь к делу, стандарт — это форма описания гарантий. После всей той драмы, которую вы тут развели про зарплату, было бы странно если бы ваше решение не предоставляло разумных гарантий надежности. И под гарантииями надежности я имею ввиду что-то сильнее чем «я попробовал и у меня работает». А теперь вы можете сказать что-нибудь по существу?
                                                                                                              • –2
                                                                                                                У меня? Бурная реакция? Мы точно один сайт сейчас читаем? Драму какую-то нашли.
                                                                                                                И в словарик загляните на букву С, что бы понимать что такое стандарт.
                                                                                                                • +2
                                                                                                                  То есть не можете. Спасибо за время потраченое зря время.
                                                                            • 0
                                                                              Если родитель нужен, пробуем ему послать SIGCHILD, но скорее всего это не поможет. Тогда цепляемся к родителю через gdb, и от родителя уже запускаем waitpid() на pid зомби-процесса:
                                                                              # gdb
                                                                              (gdb) attach 19595
                                                                              (gdb) call waitpid(19698,0,0)
                                                                              $1 = 19698
                                                                              (gdb) detach
                                                                              
                                                                            • +3
                                                                              А зачем сравнивать шелл с возможностями cmd? Не, ну серьезно? Зачем выбирать какое-то другое древнее дерьмо мамонта и сравнивать с ним?

                                                                              Если мне что-то нужно автоматизировать в windows — я возьму вовсе не cmd.
                                                                              • +9

                                                                                Ну так и на линуксе народ автоматизацию на питоне сейчас каком-нибудь пишет.

                                                                                • +1
                                                                                  Я вам больше скажу — у JavaEE контейнера Weblogic внутри тоже jython. И это удобно.

                                                                                  Разница в том, что для управления чем-то при помощи скриптов изнутри есть API, а не предлагается вызывать команды, которые вернут неструктурированный поток байтов типа stdin.

                                                                                  Ну т.е. нормальная современная полноценная автоматизация — это вовсе не шелл, в его оригинальном виде. Ну и не cmd конечно же.
                                                                                • +8

                                                                                  Ну, а если вам надо что-то автоматизировать в юниксах, то вы можете взять даже шелл. А можете любой вариант из десятков других. Но в простейш4м варианте даже на шелл можно что-то делать вменяемое.

                                                                              • +7
                                                                                Очень похоже на выдержки из Unix Haters Handbook. Прочитать эту книгу для общего развития нужно, но в работе использовать не стоит :)
                                                                                • +13

                                                                                  К сожалению, их более новые и продуманные системы, где решены многие из упомянутых проблем — OS Plan9, OS Inferno — не взлетели. Не нужны народу элегантные системы, в которых нет этих костылей — наверное, скучно без них. Я много лет работал с OS Inferno, и это буквально "открыло глаза" на многие проблемы *NIX. Пока радует только рост популярности Go, может хоть одна из их попыток хоть немного исправить сверх-популярные UNIX и C спустя 40 лет окажется относительно успешной.

                                                                                  • +2
                                                                                    Возможно redox взлетит…
                                                                                    • +9
                                                                                      К сожалению, какой бы хорошей не была система, она скорее всего не взлетит. Нужно пробить огромную инертную массу в виде существующих и как-то работающих технологий, решений, знаний и специалистов. Это зачастую гораздо сложнее чем придумать что-то новое и гениальное.
                                                                                      • +2
                                                                                        Вода камень точит…
                                                                                        • +5
                                                                                          Нужно пробить огромную инертную массу в виде существующих и как-то работающих технологий, решений, знаний и специалистов.

                                                                                          ЕМНИП, создатели Plan9 именно так и говорили. Поэтому и не взлетело.
                                                                                      • +1
                                                                                        Не нужны народу элегантные системы

                                                                                        Думаю, проблема немного не в этом. Проблема кроется в бизнесе, где хотят минимальной жертвой получить как можно больше.
                                                                                      • +24
                                                                                        Итак, я не хочу сказать, что UNIX — плохая система. Просто обращаю ваше внимание на то, что у неё есть полно недостатков, как и у других систем. И «философию UNIX» я не отменяю, просто обращаю внимание, что она не абсолют.


                                                                                        Вы критикуете недостатки полувековой давности, которые в повседневной работе уже давно обернуты современными инструментами.

                                                                                        И да, есть такое дело, «отвергаешь — предлагай». Более удобный GUI, сравнимый по производительности с Shell, новые GUI-утилиты, способные склеиваться выводом-вводом (да хоть TermKit) — и без copy-paste, так как я не хочу повторять свои «макросы» Mega-GUI-Shell руками, да еще и параметры хочу.

                                                                                        Что касается C… вас кто-то уговаривает на нём писать? Make кстати вчистую уже тоже давно никто не использует. Можно продол