Як у скриптах конфігурації оболонки, як я можу пояснити різниці між coreutils на BSD порівняно з GNU?


9

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

Я сьогодні був здивований, коли lsперестав працювати. Виявилося, що під час рефакторингу .bashrcбув псевдонім

alias ls='ls --color=always'

це зламало речі lsв баші на Терміналі в OSX. Як тільки я побачив, що BSD lsподобається -Gза кольором, але GNU (або все, що було на Ubuntu) подобається --color, було зрозуміло, що досить багато варіантів відрізняються.

Моє запитання полягає в тому, що найкращий спосіб обліку різниць у варіантах і таких варіантах між BSD та GNU coreutils? Чи слід перевірити змінну env в ifблоках, щоб побачити, яка ОС використовується та застосувати правильну поведінку? Або має сенс робити окремі конфігураційні файли для кожної ОС?

Хоча відповіді на ці запитання можуть бути суб’єктивними, здається, що усунення сфери відмінностей між BSD та GNU coreutils та стратегіями їх вирішення, щоб зробити загальну конфігурацію, придатну для використання на більшості * 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 від Ports. Це приклад, чому виконання "якщо" на $ OSTYPE не може дати бажаних результатів.
лабіринт

Чи є спосіб придушити помилку, що виникає з "if ls - перетворення", коли GNU coreutils немає (але все-таки зможете перевірити наявність coreutils)?
лабіринт

О, ніколи не майте на увазі придушення помилки. Я просто перенаправляю stderr на / dev / null, перш ніж трубопровід grep, і він працює так, як мені хотілося.
лабіринт

3
Замість того, щоб шукати coreutilsявно, чому б не просто перевірити, чи працює прапор кольорів, наприклад if ls --color=auto -d / >/dev/null 2>&1; then ....
Мікель

@mikel, якщо вас турбує лише колір (як у прикладі), це добре. Якщо ви також піклуєтесь про інші функції, корисна перевірка Coreutils.
Йорданм

3

Літеринг коду з ifвисловлюваннями для перемикання типу coreutils працює, однак чистим рішенням програмування для обробки різних типів є використання поліморфізму . Оскільки це Баш, у нас немає поліморфізму, але я плутаюся зі способом підробити це. Єдина вимога - ваш .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 (можливо, він справді старий, і вони мають файлеві файли, але не textutils). Мені б сподобалося скористатися lsвашим диспетчером, а не catтим більше, що жоден твій псевдонім не передбачає cat.
Мікель

Крім того, вам не потрібно мати --color=autoдругого та третього псевдонімів, оскільки перший псевдонім додає цю опцію до ls.
Мікель

1
@Mikel whoa, я абсолютно не усвідомлював це aliasрекурсивно. Це дозволяє мені зробити приклад набагато простішим.
Михайло Кропат

Значно краще. :-)
Мікель

0

Це не пряма відповідь на ваше запитання, але я маю сценарії обгортки, щоб обробляти такі речі, а не додаткові ускладнення в .bashrc. Наприклад, ось мій сценарій l, який обробляє ваш випадок тут крос-платформенним способом:

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

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.