В скриптах конфигурации оболочки, как я могу учесть различия между coreutils на BSD по сравнению с GNU?


9

Вплоть до этого месяца мои конфиги оболочки были довольно просты (в основном с псевдонимами .bashrcили .bash_profileс некоторыми псевдонимами), но я проводил рефакторинг, чтобы я мог получить различное поведение в зависимости от того, использую ли я zsh и bash. Сначала они получают общий конфигурационный файл оболочки, который должен работать для чего угодно, а затем специализируются на конкретной используемой оболочке (см. Ссылку на это).

Я был удивлен сегодня, когда lsперестал работать. Оказалось, что во время рефакторинга .bashrcбыл псевдоним

alias ls='ls --color=always'

это сломало вещи lsв bash на терминале в OSX. Как только я увидел, что BSD lsлюбит -Gцвет, а GNU (или что-то еще в Ubuntu) нравится --color, стало ясно, что довольно много вариантов различаются.

Мой вопрос заключается в том, каков наилучший способ учета различий в параметрах и таковых между BSD и GNU coreutils? Должен ли я проверить переменную env в ifблоках, чтобы увидеть, какая ОС используется и применить правильное поведение? Или имеет смысл создавать отдельные конфигурационные файлы для каждой ОС?

Хотя ответы на эти вопросы могут быть субъективными, это выглядит как краткое изложение различий между базовыми утилитами BSD и GNU, и стратегии, позволяющие обойти их для создания универсальной конфигурации, пригодной для использования на большинстве * nix, были бы довольно объективными.


Смена снарядов ничего не исправит и ls -cотличается от ls --color. Отредактировал ваш вопрос, чтобы исправить.
Микель

Ответы:


9

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

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

if ls --version 2>/dev/null | grep -q 'coreutils'; then
    alias ls='ls --color=always'
else
    alias ls='ls -G'
fi

Я играл с разными методами, и я думаю, что ваше "уродливое" решение довольно хорошее и даже не настолько уродливое. Как оказалось, я не заметил несоответствия в опциях для ls ранее, потому что я использовал GNU coreutils из портов. Это пример того, почему выполнение 'if' на $ OSTYPE может не дать желаемых результатов.
Лабиринт

Есть ли способ подавить ошибку, возникающую из-за «if ls --version», когда GNU coreutils отсутствует (но все же можно проверить на coreutils)?
Лабиринт

О, не говоря уже о подавлении ошибки. Я просто перенаправляю stderr в / dev / null перед тем, как отправлять сообщения в grep, и это работает так, как мне хотелось бы.
Лабиринт

3
Вместо того, чтобы искать coreutilsявно, почему бы просто не проверить, работает ли цветовой флаг, например if ls --color=auto -d / >/dev/null 2>&1; then ....
Микель

@mikel, если вас интересует только цвет (как в примере), это нормально. Если вас интересуют и другие функции, полезно проверить наличие coreutils.
Иордания

3

Засорение кода ifинструкциями для переключения типа coreutils работает, однако чистое программирующее решение для обработки различных типов заключается в использовании полиморфизма . Поскольку это Bash, у нас нет полиморфизма как такового, но я бездельничал, пытаясь подделать его. Единственное требование - чтобы ваш .bashrcфайл и т. Д. Были организованы в функции.

Сначала я создаю тест для платформы типа coreutils :

get_coreutils_platform() {
    local ls_version="$(ls --version 2>/dev/null)"
    if [[ "$ls_version" == *"GNU coreutils"* ]]; then
        echo gnu
    else
        echo bsd
    fi
}

Затем мы можем отправить на основе типа:

platform=$(get_coreutils_platform)
define_standard_aliases_$platform
configure_shell_vars_$platform

Вот реализация BSD :

define_standard_aliases_bsd() {
    define_standard_aliases
}

configure_shell_vars_bsd() {
    configure_shell_vars
    export CLICOLOR=1
}

(Обратите внимание, что мы используем CLICOLORпеременную для включения цветов вместо использования alias, которое кажется немного чище)

И GNU претворение в жизнь:

define_standard_aliases_gnu() {
    define_standard_aliases
    alias ls='ls --color=auto'
}

configure_shell_vars_gnu() {
    configure_shell_vars
}

Для полноты, вот пример реализации "абстрактной базы":

define_standard_aliases() {
    alias ll='ls -l'
    alias l.='ls -d .*'
}

configure_shell_vars() {
    export EDITOR=vim
}

Это намного чище, если только вы не используете 0.1% систем, например, с установленной GNU ls, но не с установленной GNU cat (возможно, она действительно старая и у них есть fileutils, но не textutils). Я бы соблазнился использовать lsв вашем диспетчере, а не cat, тем более, что ни один из ваших псевдонимов не включает cat.
Микель

Кроме того, вам не нужно --color=autoуказывать второй и третий псевдонимы, поскольку первый псевдоним добавляет эту опцию к ls.
Микель

1
@ Микель, я просто не поняла, что aliasэто рекурсивно. Это позволяет мне сделать пример намного проще.
Майкл Кропат

Намного лучше. :-)
Микель

0

Не прямой ответ на ваш вопрос, но у меня есть сценарии-обертки для обработки подобных вещей, а не дополнительные сложности в .bashrc. Например, вот мой сценарий l, который обрабатывает ваше дело здесь кросс-платформенным способом:

http://www.pixelbeat.org/scripts/l

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.