grepping, awking, sedding и piping — это ежедневные действия пользователя любой Unix-подобной операционной системы, будь то в командной строке или внутри сценария оболочки (совместно называемыефильтрывпредь).
По сути, при работе со «стандартными» программами CLI Unix и встроенными командами оболочки (совместно именуемымикомандыс этого момента) фильтрам нужен точный ожидаемый формат для stdin, stdout и stderr на каждом шаге фильтра для корректной работы. Я называю этот точный ожидаемый формат некоторой команды API этой команды в дальнейшем.
Как человек с опытом веб-разработки, я сравниваю этот вид сбора и обработки данных с технической точки зрения свеб-скрапинг- метод, который становится крайне нестабильным при малейшем изменении представления данных.
Теперь мой вопрос касается стабильности командных API Unix.
- Соответствуют ли команды в Unix-подобных операционных системах формальной стандартизации в отношении их ввода и вывода?
- Были ли в истории случаи, когда обновления какой-либо важной команды приводили к нарушению функциональности какого-либо фильтра, созданного с использованием старой версии этой команды?
- Неужели команды Unix со временем стали настолько зрелыми, что их абсолютно невозможно изменить таким образом, чтобы какой-то фильтр мог сломаться?
- Если фильтры могут время от времени выходить из строя из-за изменения командных API, как я как разработчик могу защитить свои фильтры от этой проблемы?
решение1
В стандарте POSIX 2008 есть раздел, описывающий«Shell и коммунальные услуги». В целом, если вы будете придерживаться этого, ваши скрипты будут достаточно надежными в будущем, за исключением, возможно, случаев устаревания, но это вряд ли произойдет в одночасье, поэтому у вас будет достаточно времени для обновления своих скриптов.
В некоторых случаях, когда формат вывода для одной утилиты сильно различается на разных платформах и версиях, стандарт POSIX может включать опцию, обычно называемую -p
или -P
, которая определяет гарантированный и предсказуемый формат вывода. Примером этого являетсяtime
полезность, который имеет широко варьирующиеся реализации. Если вам нужен стабильный формат API/вывода, вы бы использовали time -p
.
Если вам необходимо использовать утилиту фильтрации, которая не охвачена стандартом POSIX, то вы в значительной степени зависите от упаковщиков дистрибутивов/разработчиков вышестоящей ветки разработки, так же как вы зависите от удаленных веб-разработчиков при выполнении веб-скрапинга.
решение2
Попробую ответить, исходя из своего опыта.
Команды на самом деле не следуют формальной спецификации, но они следуют требованию потреблять и генерировать строчно-ориентированный текст.
Да, конечно. До того, как утилиты GNU стали фактическим стандартом, многие поставщики имели странный вывод, особенно в отношении
ps
иls
. Это вызывало много проблем. Сегодня только HP поставляет супер-странные команды. Исторически утилиты Berkeley Software Distribution (BSD) были серьезным разрывом с прошлым. Спецификация POSIX была разрывом с прошлым, но теперь она широко принята.Команды Unix действительно со временем стали более зрелыми. Все еще возможно сломать какой-нибудь скрипт, написанный для старой версии. Подумайте о недавней тенденции к UTF-8 как кодировке текстовых файлов. Это изменение потребовало изменения базовых утилит, таких как
tr
. Раньше простой текст почти всегда был ASCII (или что-то близкое), поэтому заглавные буквы образовывали числовой диапазон, как и строчные буквы. Это больше не так с UTF-8, поэтомуtr
он принимает различные параметры командной строки для указания таких вещей, как «заглавные» или «буквенно-цифровые».Один из лучших способов «упрочнить» ваши фильтры — не зависеть от конкретной раскладки текста. Например, не делайте
cut -c10-24
, которая зависит от позиций строки.cut -f2
Вместо этого используйте , что отрежет второе поле, разделенное табуляцией.awk
разбивает любую входную строку на $1, $2, $3..., которые по умолчанию разделены пробелами. Зависят от более высокоуровневых концепций, таких как «поля», а не от низкоуровневых концепций, таких как положение столбца. Кроме того, используйте регулярные выражения:sed
иawk
оба могут делать вещи с регулярными выражениями, которые не заботятся о некоторой дисперсии во входных данных. Другой трюк — обработать входные данные во что-то, к формату чего ваш фильтр может быть разборчив. Используйте ,tr -cs '[a-zA-z0-9]' '[\n]'
чтобы разбить текст на одно слово в строке, без знаков препинания. В этом случае вам просто все равно, как выглядит входной текст.
решение3
Сначала очень краткие ответы на ваши вопросы:
- Формальная стандартизация соглашений о вводе/выводе:нет
- Поломки в прошлом из-за изменения производительности:да
- Абсолютно невозможно сломать будущие фильтры:нет
- Как я могу защитить себя от изменений:быть консервативным
Когда вы говорите "API", вы используете термин, который (хорошо это или плохо) подразумевает слишком много формальности вокруг соглашений о входе/выходе фильтра. Очень (и я имею в виду "очень") широко, основные соглашения для данных, которые легко фильтруются, это
- каждая входная строка представляет собой полную запись
- внутри каждой записи поля разделяются известным символом-разделителем
Классическим примером может служить формат /etc/passwd. Но эти соглашения по умолчанию, вероятно, нарушаются в какой-то степени чаще, чем соблюдаются буквально.
- Существует множество фильтров (часто написанных на awk или perl), которые анализируют многострочные форматы ввода.
- Существует множество шаблонов ввода (например, /var/log/messages), где нет четко определенной структуры полей, и необходимо использовать более общие методы, основанные на регулярных выражениях.
Ваш четвертый вопрос, как защитить себя от изменений в структуре выпуска, на самом деле единственный, с которым вы можете что-то сделать.
- Как@jw013 сказал, посмотрите, что говорят стандарты posix. Конечно, posix не определяет все команды, которые вы захотите использовать в качестве источников ввода.
- Если вы хотите, чтобы ваши скрипты были переносимыми, постарайтесь избегать особенностей той версии команды some, которая у вас установлена. Например, многие версии GNU стандартных команд unix имеют нестандартные расширения. Они могут быть полезны, но вам следует избегать их, если вы хотите максимальной переносимости.
- Попробуйте узнать, какие подмножества аргументов команд и форматов вывода имеют тенденцию быть стабильными на разных платформах. К сожалению, это требует доступа к нескольким платформам вместе со временем, поскольку эти различия не будут нигде записаны, даже неформально.
В конце концов, вы не можете полностью защитить себя от проблем, которые вас беспокоят, и нет единого места, куда можно было бы обратиться за «окончательным» утверждением того, что должна делать определенная команда. Для многих скриптов оболочки, особенно написанных для личного или мелкомасштабного использования, это просто не проблема
решение4
Существуют только фактические стандарты ввода-вывода — вывод, разделенный пробелами и нулем.
Что касается совместимости, мы обычно возвращаемся к проверке номеров версий отдельных фильтров. Не то чтобы они сильно менялись, но когда вы хотите использовать совершенно новую функцию и при этом хотите, чтобы скрипт работал на старых версиях, вам нужно как-то "ifdef" ее вывести. Практически нет механизма отчетности о возможностях, за исключением ручного написания тестовых случаев.