Dans les scripts de configuration shell, comment puis-je tenir compte des différences entre coreutils sur BSD et GNU?

9

Jusqu'à ce mois-ci, mes configurations de shell étaient assez simples (juste un .bashrcou .bash_profileavec quelques alias principalement), mais je l'ai refactorisé pour que je puisse obtenir un comportement différent selon que j'utilise zsh et bash. Ils source d'abord un fichier de configuration de shell générique qui devrait fonctionner pour n'importe quoi, puis se spécialisent pour le shell spécifique utilisé (je fais un lien symbolique vers cela).

J'ai été surpris aujourd'hui lorsque j'ai lscessé de travailler. Il s'est avéré que lors du refactoring .bashrc, il y avait un alias

alias ls='ls --color=always'

qui cassait les choses pour lsen bash sur Terminal dans OSX. Une fois que j'ai vu que BSD lsaime la -Gcouleur, mais que GNU (ou tout ce qui était sur Ubuntu) aime --color, il était clair que plusieurs options diffèrent.

Ma question est la suivante: quelle est la meilleure façon de tenir compte des différences d'options et de telles différences entre BSD et GNU coreutils? Dois-je tester une variable env dans les ifblocs pour voir quel système d'exploitation est utilisé et appliquer le comportement correct? Ou est-il plus logique de créer des fichiers de configuration distincts pour chaque système d'exploitation?

Bien que les réponses à ces questions puissent être subjectives, il semble qu'un aperçu de la portée des différences entre les coreutils BSD et GNU et les stratégies pour les contourner afin de rendre une configuration générique utilisable sur la plupart des * nix serait assez objectif.

labyrinthe
la source
Changer les obus ne résoudra rien et ls -cest différent de ls --color. Modification de votre question à corriger.
Mikel

Réponses:

9

La seule façon fiable d'écrire des scripts qui prennent en charge différents systèmes d'exploitation est de n'utiliser que des fonctionnalités définies par POSIX.

Pour des choses comme vos configurations de shell personnelles, vous pouvez utiliser des hacks qui correspondent à votre cas d'utilisation spécifique. Quelque chose comme ce qui suit est moche, mais atteindra l'objectif.

if ls --version 2>/dev/null | grep -q 'coreutils'; then
    alias ls='ls --color=always'
else
    alias ls='ls -G'
fi
jordanm
la source
J'ai joué avec différentes méthodes, et je pense que votre solution "laide" est plutôt bonne et même pas laide. En fait, je n'avais pas remarqué la non-concordance des options pour ls plus tôt parce que j'utilisais des coreutils GNU de Ports. C'est un exemple pour lequel faire un «si» sur $ OSTYPE peut ne pas fournir les résultats souhaités.
labyrinthe
Existe-t-il un moyen de supprimer l'erreur provenant de "if ls --version" lorsque les coreutils GNU ne sont pas présents (mais peuvent toujours tester les coreutils)?
labyrinthe
Oh, pas question de supprimer l'erreur. Je redirige simplement stderr vers / dev / null avant de passer à grep et cela fonctionne comme je le voudrais.
labyrinthe
3
Plutôt que de chercher coreutilsexplicitement, pourquoi ne pas simplement tester si le drapeau de couleur fonctionne, par exemple if ls --color=auto -d / >/dev/null 2>&1; then ....
Mikel
@mikel si vous ne vous souciez que de la couleur (comme dans l'exemple), c'est bien. Si vous vous souciez également d'autres fonctionnalités, la vérification des coreutils est utile.
jordanm
3

Littering le code avec des ifinstructions pour effectuer un changement sur le type de coreutils fonctionne, mais la solution de programmation propre pour gérer différents types est d'utiliser le polymorphisme . Comme il s'agit de Bash, nous n'avons pas de polymorphisme en soi, mais j'ai essayé de trouver un moyen de le simuler. La seule exigence est que votre .bashrcfichier, etc. soit organisé en fonctions.

Je crée d'abord un test pour le type de plateforme coreutils :

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

Ensuite, nous pouvons expédier en fonction du type:

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

Voici l' implémentation BSD :

define_standard_aliases_bsd() {
    define_standard_aliases
}

configure_shell_vars_bsd() {
    configure_shell_vars
    export CLICOLOR=1
}

(Notez que nous utilisons la CLICOLORvariable pour activer les couleurs au lieu d'utiliser un alias, qui semble plus propre)

Et l' impelementation GNU :

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

configure_shell_vars_gnu() {
    configure_shell_vars
}

Par souci d'exhaustivité, voici un exemple d'implémentation de la "base abstraite":

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

configure_shell_vars() {
    export EDITOR=vim
}
Michael Kropat
la source
C'est beaucoup plus propre, sauf si vous êtes sur 0,1% des systèmes avec par exemple GNU ls mais pas GNU cat installé (peut-être qu'il est vraiment vieux et qu'ils ont des fileutils mais pas des textutils). Je serais tenté d'utiliser lsplutôt dans votre répartiteur que cat, d'autant plus qu'aucun de vos alias n'implique cat.
Mikel
De plus, vous ne devriez pas avoir besoin --color=autode vos deuxième et troisième alias, car le premier alias ajoute cette option à ls.
Mikel
1
@Mikel whoa, je ne savais absolument pas que aliasc'était récursif. Cela me permet de rendre l'exemple beaucoup plus simple.
Michael Kropat du
Bien mieux. :-)
Mikel
0

Pas une réponse directe à votre question, mais j'ai des scripts wrapper pour gérer des choses comme ça plutôt que des complications supplémentaires dans le .bashrc Par exemple, voici mon script l qui gère votre cas ici d'une manière multiplateforme:

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

Pádraig Brady
la source