Насколько стабильны «API-интерфейсы stdin / stdout» оболочки Unix?

20

grepping, awking, sedding и piping - это повседневная рутина пользователя любой Unix-подобной операционной системы, может ли это быть в командной строке или внутри сценария оболочки ( теперь они называются фильтрами ).

По своей сути, при работе со «стандартными» программами Unix CLI и встроенными командами оболочки ( теперь они называются командами ), для правильной работы фильтрам необходим точный ожидаемый формат для stdin, stdout и stderr на каждом шаге фильтра. Этот точный ожидаемый формат некоторых команд я называю API этой команды в следующем.

Как человек, имеющий опыт веб-разработки, я сравниваю этот вид сбора и обработки данных с технической точки зрения со соскобом в Интернете - метод, который очень нестабилен при малейших изменениях в представлении данных.

Мой вопрос сейчас касается стабильности API команд Unix.

  1. Придерживаются ли команды в Unix-подобных операционных системах формальной стандартизации в отношении их ввода и вывода?
  2. Были ли в истории случаи, когда обновления какой-либо важной команды приводили к нарушению функциональности какого-либо фильтра, созданного с использованием более старой версии этой команды?
  3. Создались ли у Unix команды со временем, что абсолютно невозможно изменить таким образом, чтобы какой-то фильтр мог сломаться?
  4. Если фильтры могут время от времени выходить из строя из-за изменения командных API, как я, как разработчик, могу защитить свои фильтры от этой проблемы?
Abdull
источник

Ответы:

17

В стандарте POSIX 2008 есть раздел, описывающий «Оболочка и утилиты» . Как правило, если вы придерживаетесь этого, ваши сценарии должны быть достаточно ориентированы на будущее, за исключением, возможно, устаревших, но это вряд ли произойдет в одночасье, поэтому у вас должно быть достаточно времени для обновления ваших сценариев.

В некоторых случаях , когда формат вывод для одной утилиты широко варьируется в зависимости от платформы и версии, стандарт POSIX , может включать в себя вариант , как правило , называемом -pили -Pкоторый определяет гарантированный и предсказуемый выходной формат. Примером этого является timeутилита , которая имеет различные реализации. Если вам нужен стабильный API / выходной формат, вы должны использовать time -p.

Если вам нужно использовать утилиту фильтрации, которая не охвачена стандартом POSIX, то вы в значительной степени зависите от разработчиков дистрибутивов / разработчиков, так же как и от удаленных веб-разработчиков при работе с веб-утилитами.

jw013
источник
12

Я постараюсь ответить из моего опыта.

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

  2. Да, конечно. До того, как утилиты GNU станут стандартом де-факто, многие поставщики получат причудливый вывод, особенно в отношении psи ls. Это вызвало много боли. Сегодня только HP предоставляет сверхъестественные команды. Исторически сложилось так, что утилиты Berkeley Software Distribution (BSD) были серьезным разрывом с прошлым. Спецификация POSIX порвала с прошлым, но теперь она широко принята.

  3. Команды Unix действительно созрели со временем. Все еще не невозможно сломать некоторый сценарий, написанный для более старой версии. Подумайте о недавней тенденции к UTF-8 как кодировке текстовых файлов. Это изменение потребовало изменения основных утилит, таких как tr. В прошлом простой текст почти всегда был ASCII (или чем-то близким), поэтому заглавные буквы образовывали числовой диапазон, как и строчные буквы. Это больше не относится к UTF-8, поэтому он trпринимает различные параметры командной строки, чтобы указать такие вещи, как «прописные» или «буквенно-цифровые».

  4. Один из лучших способов «прорезать» ваши фильтры - не зависеть от конкретной текстовой разметки. Например, не делайте cut -c10-24, что зависит от положения линии. Используйте cut -f2вместо этого, что бы отрубить 2-ое, разделенное табуляцией поле. awkразбивает любую строку ввода на $ 1, $ 2, $ 3 ..., которые по умолчанию разделены пробелами. Зависит от понятий более высокого уровня, таких как «поля», а не от понятий более низкого уровня, таких как положение столбца. Кроме того, используйте регулярные выражения: sedи они awkмогут делать что-то с регулярными выражениями, которые не заботятся о некоторой дисперсии ввода. Еще одна хитрость заключается в обработке входных данных во что-то, чей формат ваш фильтр может быть разборчивым. Используется tr -cs '[a-zA-z0-9]' '[\n]'для разбиения текста на одно слово в строке без пунктуации. Вы просто не

Брюс Эдигер
источник
9

Сначала очень краткие ответы на ваши вопросы:

  1. Формальная стандартизация соглашений ввода / вывода: нет
  2. Поломка в прошлом из-за изменения выхода: да
  3. Абсолютно невозможно сломать будущие фильтры: нет
  4. Как я могу защитить себя от изменений: быть консервативным

Когда вы говорите «API», вы используете термин, который (хорошо это или плохо) подразумевает слишком много формальностей в соглашениях фильтра ввода / вывода. Очень (и я имею в виду «очень») в широком смысле, основными соглашениями для данных, которые можно легко фильтровать, являются:

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

Классическим примером будет формат / etc / passwd. Но эти соглашения по умолчанию, вероятно, нарушаются в некоторой степени чаще, чем они соблюдаются в букве.

  • Существует множество фильтров (часто написанных на awk или perl), которые анализируют многострочные форматы ввода.
  • Существует множество шаблонов ввода (например, / var / log / messages), в которых нет четко определенной структуры полей, и необходимо использовать более общие методы на основе регулярных выражений.

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

  • Как сказал @ jw013 , посмотрите, что говорят стандарты posix. Конечно, posix не указывает все команды, которые вы хотите использовать в качестве источников ввода.
  • Если вы хотите, чтобы ваши сценарии были переносимыми, постарайтесь избежать специфических особенностей той или иной версии команды, которую вы случайно не установили. Например, многие версии GNU стандартных команд unix имеют нестандартные расширения. Это может быть полезно, но вы должны избегать их, если вы хотите максимальной мобильности.
  • Попробуйте узнать, какие подмножества командных аргументов и форматов вывода имеют тенденцию быть стабильными на разных платформах. К сожалению, это требует доступа к нескольким платформам вместе со временем, потому что эти различия не будут записаны нигде, даже в неофициальном порядке.

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

Дейл Хагглунд
источник
5

Только покрытие 1) вашего вопроса.

Естественно, API-интерфейсы всегда могут изменяться по желанию их создателей и, таким образом, нарушать зависимое программное обеспечение на любом языке. Тем не менее, отличная идея API-интерфейсов ввода / вывода инструментов Unix заключается в том, что их практически нет (возможно, 0x0aв конце строки). Хороший скрипт фильтрует данные с помощью инструментов Unix, а не создает их. Это означает, что ваш скрипт может сломаться из-за изменения спецификации ввода или вывода, но не потому, что изменился формат ввода / вывода (опять же, на самом деле его нет) отдельных инструментов, используемых в скрипте (потому что что-то, чего на самом деле не существует) не может действительно измениться).

Просматривая список базовых инструментов, я бы также отнес атрибут производителя к списку основных инструментов , а не только к фильтру:

  • Туалет - вывести количество байтов, слов, строк - очень простой формат, поэтому вряд ли изменится, и, кроме того, вряд ли будет использоваться в скрипте.
  • diff - есть разные форматы вывода, но я не слышал о каких-либо проблемах. Также обычно не используется без присмотра.
  • свидание - теперь здесь мы действительно должны позаботиться о том, что мы производим, особенно в отношении локали системы. Но в противном случае выходной формат RFC, если вы не укажете его сами.
  • кал - давайте не будем об этом, я знаю, что выходной формат очень сильно отличается в разных системах.
  • LS , кто , W , последний - я не могу помочь, если вы хотите разобрать ls, это просто не должно было быть. Кроме того, кто, w, последний, являются более интерактивными списками; Если вы используете их в сценарии, вы должны позаботиться о том, что вы делаете.
  • время было указано в другом посте. Но да, это так же, как с ls. Больше для интерактивного / локального использования. И встроенная bash сильно отличается от версии GNU, а версия GNU имеет нефиксированные ошибки в течение многих лет. Просто не надейся на это.

Вот инструменты, которые ожидают, что конкретный формат ввода более специфичен, чем поток байтов:

  • Ьс , постоянный ток - калькуляторы. Уже на более хакерской стороне вещей (на самом деле, я не использую их в скриптах) и, вероятно, очень стабильные форматы ввода / вывода.

Есть еще одна область с гораздо более высоким риском поломки, а именно интерфейс командной строки. Большинство инструментов имеют разные функции как в разных системах, так и во временной шкале. Примеры

  • Все инструменты, использующие регулярное выражение - regex могут изменять значение в зависимости от языкового стандарта системы (например, LC_COLLATE), и в реализациях regex есть много тонкостей и особенностей.
  • Просто не используйте модные переключатели. Вы можете легко использовать, man 1p findнапример, чтобы прочитать man-страницу POSIX find вместо системной man-страницы. В моей системе мне нужно установить manpages-posix.

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

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

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

Джо Со
источник
1

Существуют только де-факто стандарты ввода-вывода - пробелы и разделенные нулями выходные данные.

Что касается совместимости, мы обычно возвращаемся к проверке номеров версий отдельных фильтров. Не то чтобы они сильно изменились, но когда вы хотите использовать совершенно новую функцию и все же хотите, чтобы скрипт работал на более старых версиях, вы должны каким-то образом «определить» его. Практически отсутствует механизм отчетности о возможностях, за исключением написания тестовых случаев вручную.

lynxlynxlynx
источник
0

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

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

Алекс Чемберлен
источник