Люби друга, но помни, что он может стать тебе врагом (Сципион).

Почему команды Linux не всегда работают в macOS


Почему команды Linux не всегда работают в macOS

Вы когда-нибудь задумывались, почему команда отлично работает в Linux, но не работает в macOS? Например, эта команда должна была сработать в Linux:

sed -i 's/debug=true/debug=false/' config.ini

 

Мы несколько раз запускали эту команду в Linux. Она всегда работала.

Однако та же команда не сработала в macOS. Мы проверили синтаксис, проверил файл и снова запустил команду. Но это не сработало.

И Linux, и macOS предоставляют среду командной строки, похожую на Unix. Из-за этого сходства легко предположить, что команды Linux будут работать так же в терминале macOS. Часто так и происходит, но не всегда.

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

 

Поначалу все кажется знакомым

Неработающая команда sed не была случайным исключением. Большинство команд Linux работают в macOS без каких-либо изменений.

Такая согласованность порождает ожидания. Если одна команда работает, то и следующая тоже должна работать.

Эти ожидания вполне обоснованны. И Linux, и macOS предоставляют Unix-подобную среду командной строки. Unix-подобная операционная система во многом следует интерфейсам и принципам проектирования, заложенным в Unix. В результате обе системы предоставляют множество одинаковых инструментов командной строки и знакомых схем расположения каталогов.

Откройте терминал macOS, и вы увидите такие знакомые команды, как ls, cd, pwd, cp, mv и ssh. Вы также найдете знакомые каталоги, такие как /usr, /etc, /var и /tmp.

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

Именно с этого предположения и начинаются различия.

 

Одна и та же команда не всегда означает одну и ту же программу

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

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

В Linux такие команды, как sed, grep, find, и tar обычно взяты из утилит GNU. Утилит GNU — это набор инструментов командной строки, разработанный в рамках проекта GNU.

В macOS многие из этих команд взяты из утилит BSD. Утилит BSD предоставляют те же базовые функции, но они были разработаны независимо. В результате некоторые параметры, значения по умолчанию и функции различаются.

Рассмотрим команду sed из вступления.

В Linux:

sed -i 's/debug=true/debug=false/' config.ini

 

При выполнении приведенной выше команды в macOS возникает ошибка следующего вида:

sed: 1: "config.ini": extra characters at the end of s command

 

Это происходит потому, что BSD sed интерпретирует config.ini как аргумент суффикса резервной копии, после чего ему уже нечего рассматривать как реальный файл, поэтому он пытается прочитать s/debug=true/debug=false/ как файл/скрипт и выдает ошибку.

Чтобы это работало в macOS, вам нужно указать пустую строку в качестве явного аргумента суффикса резервной копии:

sed -i '' 's/debug=true/debug=false/' config.ini

 

Обе команды редактируют файл на месте. Разница заключается в опции -i. Опция -i не определена в стандарте POSIX. GNU sed и BSD sed добавили ее независимо друг от друга, и в каждой из них используется свой синтаксис. GNU sed позволяет использовать -i без расширения для создания резервной копии. BSD sed требует расширения для создания резервной копии. Пустая строка ('') указывает BSD sed не создавать резервную копию.

sed Это лишь один пример. Такие команды, как find, date, stat, xargs и tar также включают расширения, характерные для GNU и BSD. Большинство различий незначительны. Они становятся важными, когда вы копируете команды между Linux и macOS или пишете сценарии командной оболочки, которые должны работать в обеих системах.

 

Ключевой вывод:

Название команды часто совпадает. А вот реализация может отличаться. Это различие объясняет многие различия в командах между Linux и macOS.

 

Когда сценарии командной оболочки перестают быть переносимыми

Команда, которая работает в терминале, не всегда переносима в сценарии командной оболочки.

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

Некоторые различия приводят к немедленному возникновению ошибки. Обычно их легко исправить.

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

Рассмотрим эту команду:

find . -type f -printf '%f\n'

 

Во многих системах Linux выводится имя каждого соответствующего файла.

В macOS это не удается, потому что реализация BSD find не поддерживает -printf опцию. -printf это расширение GNU, а не часть стандарта POSIX.

Если вы запустите приведенную выше команду в macOS (BSD find), вы получите сообщение об ошибке, подобное приведенному ниже:

find: -printf: unknown primary or operator

 

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

Если скрипт должен работать и в Linux, и в macOS, по возможности пишите его в соответствии со стандартом POSIX. POSIX определяет общий набор интерфейсов для Unix-подобных операционных систем. Функции, выходящие за рамки этого стандарта, часто называемые расширениями, могут отсутствовать на другой платформе или работать иначе. Apple рекомендует избегать платформозависимых расширений при написании кроссплатформенных скриптов.

 

Ключевой вывод:

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

 

Почему sudo не всегда решает проблему

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

В macOS такой подход работает не всегда.

Вы все равно можете увидеть такую ошибку:

Operation not permitted

 

даже при выполнении команды с sudo.

Причина в том, что macOS добавляет уровни безопасности, выходящие за рамки традиционных разрешений на доступ к файлам в Unix.

Один из таких уровней — защита целостности системы (System Integrity Protection, SIP). SIP защищает критически важные части операционной системы от изменений. Она также ограничивает внесение изменений в защищенные файлы и каталоги даже для процессов, запущенных с правами суперпользователя. Apple разработала SIP, чтобы снизить влияние вредоносного программного обеспечения и случайных изменений в системе.

Другой уровень — прозрачность, согласие и контроль (Transparency, Consent, and Control, TCC). TCC — это система защиты конфиденциальности от Apple. Она контролирует доступ к конфиденциальным пользовательским данным, таким как папки «Рабочий стол», «Документы» и «Загрузки». TCC оценивает приложение, запрашивающее доступ, а не только учетную запись пользователя, выполняющего команду.

Вот почему sudo иногда недостаточно. Команда в Терминале может не сработать, если самому Терминалу не предоставлено разрешение на доступ к защищенным данным. Во многих случаях предоставление полного доступа к диску Терминалу или вашему терминальному приложению устраняет ошибки доступа, связанные с TCC.

Не каждая Operation not permitted ошибка вызвана SIP или TCC. Традиционные разрешения для файлов, флаги файлов или другие политики безопасности также могут приводить к возникновению такой же ошибки. Однако для пользователей Linux, переходящих на macOS, SIP и TCC являются одними из самых распространенных причин того, что sudo работает не так, как ожидалось.

Ключевой вывод:

В Linux для решения проблемы с разрешениями часто достаточно sudo . В macOS повышенные привилегии — это лишь часть модели безопасности. SIP и TCC по-прежнему могут препятствовать доступу команды к защищенным ресурсам или их изменению.

 

Как разработчики Linux адаптируются к macOS

Опытные разработчики редко пытаются сделать так, чтобы macOS вела себя в точности как Linux. Вместо этого они создают предсказуемую среду разработки.

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

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

Одна из распространенных установок — GNU Coreutils. GNU Coreutils — это набор стандартных утилит командной строки, включая ls, cp, mv, и sort. Чтобы избежать конфликтов с утилитами BSD, которые есть в macOS, Homebrew устанавливает многие команды с префиксом g, например gls и gcp. Если вы предпочитаете стандартные названия команд, вы можете настроить PATH так, чтобы она искала gnubin в каталоге Homebrew перед системными каталогами.

Тот же подход применим к другим утилитам GNU, включая gnu-sed, grep, и findutils. После их установки становятся доступны реализации GNU. Ваша оболочка использует их только в том случае, если вы вызываете команду с префиксом, например gsed, или настраиваете PATH так, чтобы приоритет отдавался версии GNU.

Установка утилит GNU не меняет принцип работы macOS. Она меняет только то, какую реализацию запускает ваша оболочка.

Ключевой вывод:

Homebrew делает доступными инструменты GNU, но PATH определяет, какую реализацию запускает ваша оболочка. Предсказуемая среда разработки начинается с понимания того, к какому исполняемому файлу приводят ваши команды.

 

Заключение

В Linux и macOS много общих команд, поскольку обе системы предоставляют среду командной строки, аналогичную Unix. Из-за этого сходства легко ожидать одинакового поведения.

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

Этот же принцип объясняет остальные замеченные вами различия. Некоторые из них связаны с утилитами GNU и BSD. Другие — с функциями безопасности macOS, такими как защита целостности системы (System Integrity Protection, SIP) и прозрачность, согласие и контроль (Transparency, Consent, and Control, TCC). Сценарии командной оболочки становятся менее переносимыми, если зависят от расширений, которые доступны не везде.

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

Как только вы это поймете, отладка станет намного проще. Вместо того чтобы спрашивать: «Почему эта команда не сработала?», спросите: «Какие предположения делает эта команда о платформе?»

Такой вопрос обычно позволяет получить ответ гораздо быстрее.

Ключевой вывод:

В Linux и macOS много команд с одинаковыми названиями, но они не всегда ведут себя одинаково. Понимание реализации, стандарта и операционной системы, лежащих в основе команды, — самый надежный способ объяснить, почему она ведет себя по-разному.

 

Часто задаваемые вопросы

Нет. macOS не основана на Linux. macOS построена на Darwin, операционной системе с открытым исходным кодом от Apple. Darwin сочетает в себе ядро XNU с компонентами, созданными на основе BSD и других проектов с открытым исходным кодом. Linux и macOS — обе Unix-подобные операционные системы, но они используют разные ядра и разные утилиты командной строки.

Большинство дистрибутивов Linux включают GNUsed, а macOS — BSDsed.

Обе команды поддерживают редактирование на месте, но используют разный синтаксис для опции -i . GNU sed позволяет использовать -i без расширения резервной копии. BSD sed требует расширения резервной копии. Если вам не нужна резервная копия, укажите пустую строку:

sed -i '' 's/foo/bar/' file.txt

-printf — это расширение GNU.

Реализация find в BSD, включенная в macOS, не поддерживает его, поскольку оно не входит в спецификацию POSIX.

И в Linux, и в macOS есть Unix-подобная среда командной строки, поэтому названия многих команд совпадают. Однако лежащие в их основе реализации часто различаются. В большинстве дистрибутивов Linux используются утилиты GNU, а в macOS — утилиты BSD. Несмотря на то, что обе системы соответствуют стандарту POSIX в части основного поведения, они поддерживают различные расширения, опции и значения по умолчанию.

sudo предоставляет повышенные привилегии, но в macOS также используются дополнительные механизмы безопасности. Например, защита целостности системы (System Integrity Protection, SIP) защищает критически важные части операционной системы, а прозрачность, согласие и контроль (Transparency, Consent, and Control, TCC) — доступ к конфиденциальным пользовательским данным. Эти механизмы могут блокировать доступ, даже если команда выполняется с правами суперпользователя.

Не каждая Operation not permitted ошибка вызвана SIP или TCC, но именно из-за них пользователи Linux сталкиваются с проблемами с разрешениями в macOS.

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

Многие разработчики устанавливают утилиты GNU с помощью Homebrew и настраивают свою оболочку для использования этих инструментов. Это снижает вероятность проблем с совместимостью, но macOS по-прежнему использует собственное ядро, модель безопасности и системные утилиты по умолчанию.

Обычно нет. Homebrew устанавливает утилиты GNU вместе с утилитами BSD, которые поставляются с macOS. Во многих инструментах версия GNU использует префикс g, например gsed, поэтому она не конфликтует с системной версией. Вы можете настроить PATH так, чтобы ваша оболочка предпочитала реализацию GNU.

Используйте:

command -v sed

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

which sed

Во многих системах есть which, но command -v — более универсальный вариант для сценариев оболочки.

По возможности используйте функции POSIX. Избегайте специфичных для GNU или BSD расширений, если только ваш скрипт не предназначен для конкретной операционной системы. Если ваш скрипт должен работать как в Linux, так и в macOS, протестируйте его на обеих платформах, а не полагайтесь на идентичное поведение.

POSIX (Portable Operating System Interface, переносимый интерфейс операционной системы) — это стандарт, определяющий общие интерфейсы и поведение Unix-подобных операционных систем. Он определяет, как должны работать команды и системные вызовы, но при этом позволяет реализациям добавлять собственные расширения.

POSIX определяет общую основу, а не все функции. Многие часто используемые параметры являются расширениями GNU или BSD и не входят в стандарт. Таким образом, разные реализации могут предоставлять дополнительные функции, оставаясь при этом совместимыми со стандартом POSIX.

Утилиты GNU — это инструменты командной строки, разработанные в рамках проекта GNU и широко используемые в Linux.

Утилиты BSD созданы в рамках проекта Berkeley Software Distribution (BSD) и входят в состав macOS.

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

Переносимый скрипт оболочки по возможности не использует расширения, специфичные для GNU или BSD. Он опирается на функции, определенные стандартом POSIX, и тестируется на всех операционных системах, которые, как ожидается, будут его поддерживать.

Защита целостности системы (SIP) — это функция безопасности macOS, которая защищает критически важные системные файлы и каталоги от изменения даже процессами, запущенными с правами суперпользователя.

«Прозрачность, согласие и контроль» (Transparency, Consent, and Control, TCC) — это концепция конфиденциальности от Apple. Она контролирует доступ приложений к конфиденциальным пользовательским данным, таким как файлы в папках «Рабочий стол», «Документы» и «Загрузки», и требует согласия пользователя перед предоставлением доступа.

Права доступа в Unix определяют, есть ли у пользователя разрешение на доступ к файлу.

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

В macOS обе проверки должны пройти успешно.

Homebrew — это менеджер пакетов для macOS. Он устанавливает программное обеспечение и управляет им, не заменяя утилиты, предоставляемые операционной системой.

Homebrew устанавливает множество утилит GNU с префиксом g, таких как gsed и gcp, чтобы избежать конфликтов с версиями BSD, уже включенными в macOS.

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

Установка утилит GNU делает их доступными. Оболочка продолжает использовать тот исполняемый файл, который указан первым в PATH. Если PATH не будет обновлено или команда GNU не будет вызвана явно (например, gsed), будет запущена версия для BSD.

Редактор: AndreyEx

Если статья понравилась, поделитесь ей в социальных сетях

Оставить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

4 × 1 =

Это может быть вам интересно


Спасибо!

Теперь редакторы в курсе.

Прокрутить страницу до начала