Является ли [..] совместимым с POSIX, а [[..]] – нет?

Вопрос или проблема

Я где-то читал, что конструкция [..] в shell-скрипте, такая как [ -e $HOME/temp ], соответствует стандарту POSIX. В то время как конструкция [[..]], например [[ -e $HOME/temp ]], не соответствует ему.

Это правда?

Помимо соответствия POSIX, есть ли что-то, что делает [..] более выгодным по сравнению с [[..]]? Или наоборот?

Да, утилита [, также известная как test, является стандартной. Вы можете найти HTML-версию ее спецификации POSIX 2024 на сайте OpenGroup.

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

В разделе обоснование вы можете увидеть следующее:

Условная команда, основанная на KornShell (двойные квадратные скобки [[]]), была удалена из описания языка команд оболочки в раннем предложении. Были выдвинуты возражения, что настоящая проблема заключается в неправильном использовании команды теста ([), и вводить ее в оболочку — неправильный способ решения проблемы. Вместо этого, надлежащая документация и новое резервированное слово оболочки (!) достаточно. Позже предложение добавить [[]] в Вопросе 8 также было отклонено, потому что существующие реализации оказались подверженными ошибкам так же, как и исторические версии теста, и также было слишком много вариаций в поведении между оболочками, которые поддерживают его.

Некоторые из соответствующих различий между [[...]] и [:

  • Комбинировать более одного теста в одной инвокации надежнее с помощью [[...]], чем с [...] (где операторы -a/-o фактически устарели, поскольку их нельзя использовать надежно), но использование [ ... ] && [ ... ] || [ ... ] вполне допустимо и не несет штрафов, так как [ всегда встроен, что делает [[...]] собственные &&/|| избыточными (и потенциально запутанными, так как правила приоритета отличаются от &&/|| в оболочке).
  • [[ $string = $pattern ]] действительно выполняет сопоставление с образцом, а не сравнение на равенство. Это избыточно, так как стандартная конструкция case может сделать то же самое, и это является источником ошибок, поскольку люди склонны считать, что оставлять переменные без кавычек внутри [[...]] нормально (что часто так), и забывать использовать [[ $string1 = "$string2" ]] при сравнении строк на равенство.
  • Ситуация ухудшается с [[ $string =~ $pattern ]], что реализуется по-разному в зависимости от оболочки. bash и несколько других оболочек сделали неудачное решение, дав кавычкам влиять на операцию regex, что неверно, так как синтаксис regex несовместим с обычной токенизацией оболочки (детали можно найти в Как хранение регулярного выражения в переменной оболочки избегает проблем с кавычками, которые являются специальными для оболочки? и в упомянутой выше ошибке группы Остина). У встроенного [ в zsh и yash также есть оператор =~.
  • В большинстве оболочек арифметические операторы [[...]] интерпретируют свои операнды как арифметические выражения (что создает уязвимость для инъекций команд для [[ $1 -eq $2 ]] в большинстве оболочек (и вызывает сюрпризы, когда числа начинаются с 0, что делает их интерпретируемыми как восьмеричные в некоторых оболочках). В то время как POSIX требует, чтобы операнды для [ рассматривались как десятичные целые числа.
  • Правила разбора в [[...]] специфичны для конструкции и варьируются от оболочки к оболочке, в то время как [ является просто простой командой и обрабатывается как любая другая команда.

Таким образом, [ обычно нормально, и, чтобы процитировать POSIX, настоящая проблема заключается в неправильном использовании команды test ([).

Пока вы помните, что нужно заключать переменные и другие расширения в кавычки (как это требуется для всех команд, а не только для [) и не используете устаревшие бинарные операторы -a (и), -o (или) (и (...), которые не нужны, once you can’t combine more than one test), [ вполне безопасен (и надежнее при сравнению чисел).

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

Ответ или решение

Да, это правда, что конструкция [ ... ] (также известная как test) является совместимой с POSIX, тогда как конструкция [[ ... ]] не является таковой. Как вы правильно заметили, утилита [ входит в стандарт POSIX, что можно подтвердить, ознакомившись с публикацией на сайте The Open Group.

Были предложения добавить конструкцию [[ ... ]], происходящую из KornShell, в описание языка POSIX, однако они были отклонены. В принципе, возражения касались того, что реальная проблема заключалась в неправильном использовании команды test, и вместо этого предлагалось обеспечить адекватную документацию и ввести новое зарезервированное слово в оболочку.

Вот некоторые из основных различий между [[ ... ]] и [ ... ]:

  1. Объединение условий: С конструкцией [[ ... ]] проще и надежнее комбинировать несколько условий в одной команде, в то время как для [ ... ] использование операторов -a (AND) и -o (OR) считается устаревшим и ненадежным, что приводит к путанице.

  2. Сравнение строк и паттернов: В конструкции [[ ... ]] оператор = выполняет сопоставление с шаблоном, а не стандартное сравнение. Это может привести к ошибкам, если забыть про кавычки около переменных.

  3. Регулярные выражения: Оператор =~ в конструкции [[ ... ]] выполняет сопоставление с регулярным выражением, но реализация может отличаться в разных оболочках, что создает дополнительные сложности.

  4. Арифметические операторы: В [[ ... ]] операторы арифметики интерпретируют свои операнды как арифметические выражения, что может создать уязвимости. В отличие от этого, POSIX требует обработки операндов в [ ... ] как десятичных целых чисел.

  5. Правила парсинга: Правила парсинга для [[ ... ]] специфичны и могут варьироваться между оболочками, в то время как [ ... ] обрабатывается как обычная команда.

В отношении преимуществ, у конструкции [ ... ] есть определенные плюсы. Она является стандартной и поддерживается во всех POSIX-совместимых средах, что делает ваши скрипты более переносимыми. При правильном использовании (т.е. с кавычками и избеганием устаревших операторов) [ ... ] может быть безопасным и эффективно.

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

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

Оцените материал
Добавить комментарий

Капча загружается...