En los scripts de configuración de shell, ¿cómo puedo explicar las diferencias entre coreutils en BSD en comparación con GNU?

9

Hasta este mes, mis configuraciones de shell han sido bastante simples (solo un .bashrco .bash_profilecon algunos alias principalmente), pero lo he refactorizado para que pueda obtener un comportamiento diferente dependiendo de si estoy usando zsh y bash. Primero obtienen un archivo de configuración de shell genérico que debería funcionar para lo que sea, luego se especializan para el shell específico que se está utilizando (enlace simbólico a esto).

Hoy me sorprendió cuando lsdejé de trabajar. Resultó que durante la refactorización .bashrc, había un alias

alias ls='ls --color=always'

eso fue romper cosas para lsbash en Terminal en OSX. Una vez que vi que a BSD lsle gusta el -Gcolor, pero a GNU (o lo que sea que estaba en Ubuntu) le gusta --color, quedó claro que algunas opciones difieren.

Mi pregunta es, ¿cuál es la mejor manera de explicar las diferencias en las opciones y tales entre los coreutils de BSD y GNU? ¿Debo probar una variable env en ifbloques para ver qué sistema operativo se está utilizando y aplicar el comportamiento correcto? ¿O tiene más sentido crear archivos de configuración separados para cada sistema operativo?

Si bien las respuestas a estas preguntas pueden ser subjetivas, parece que un resumen del alcance de las diferencias entre los coreutils de BSD y GNU y las estrategias para solucionarlos para hacer que una configuración genérica sea utilizable en la mayoría de * nix sería bastante objetivo.

laberinto
fuente
Cambiar los caparazones no solucionará nada, y ls -ces diferente de ls --color. Editó su pregunta para arreglarla.
Mikel

Respuestas:

9

La única forma confiable de escribir scripts que admitan diferentes sistemas operativos es usar solo las características definidas por POSIX.

Para cosas como sus configuraciones personales de shell, puede usar hacks que se adapten a su caso de uso específico. Algo como lo siguiente es feo, pero logrará el objetivo.

if ls --version 2>/dev/null | grep -q 'coreutils'; then
    alias ls='ls --color=always'
else
    alias ls='ls -G'
fi
jordanm
fuente
He estado jugando con diferentes métodos, y creo que su solución "fea" es bastante buena y ni siquiera tan fea. Como resultado, no había notado la falta de coincidencia en las opciones de ls antes porque estaba usando GNU coreutils de Ports. Este es un ejemplo de por qué hacer un 'if' en $ OSTYPE puede fallar en entregar los resultados deseados.
laberinto
¿Hay alguna forma de suprimir el error que proviene de "if ls --version" cuando los coreutils de GNU no están presentes (pero aún así pueden probar coreutils)?
laberinto
Oh, no importa suprimir el error. Simplemente redirijo stderr a / dev / null antes de conectarlo a grep y funciona como me gustaría.
laberinto
3
En lugar de buscar coreutilsexplícitamente, ¿por qué no solo probar si la bandera de color funciona, por ejemplo if ls --color=auto -d / >/dev/null 2>&1; then ...?
Mikel
@mikel si solo le preocupa el color (como en el ejemplo), está bien. Si también le interesan otras funciones, es útil buscar coreutils.
jordanm
3

Cubrir el código con ifdeclaraciones para realizar un cambio en el tipo de coreutils funciona, sin embargo, la solución de programación limpia para manejar diferentes tipos es usar polimorfismo . Como se trata de Bash, no tenemos polimorfismo per se, pero he estado jugando con una forma de fingirlo. El único requisito es que su .bashrcarchivo, etc., esté organizado en funciones.

Primero creo una prueba para el tipo de plataforma coreutils :

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

Luego podemos enviar según el tipo:

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

Aquí está la implementación de BSD :

define_standard_aliases_bsd() {
    define_standard_aliases
}

configure_shell_vars_bsd() {
    configure_shell_vars
    export CLICOLOR=1
}

(Tenga en cuenta que usamos la CLICOLORvariable para activar los colores en lugar de usar un alias, que parece un poco más limpio)

Y la impelementación de GNU :

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

configure_shell_vars_gnu() {
    configure_shell_vars
}

Para completar, aquí hay una implementación de muestra de la "base abstracta":

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

configure_shell_vars() {
    export EDITOR=vim
}
Michael Kropat
fuente
Esto es mucho más limpio, a menos que esté en el 0.1% de los sistemas con, por ejemplo, GNU ls pero no GNU cat instalado (tal vez sea realmente antiguo y tengan fileutils pero no textutils). Estaría tentado a usarlo lsen su despachador en lugar de hacerlo cat, especialmente porque ninguno de sus alias implica cat.
Mikel
Además, no debería necesitar --color=autoen su segundo y tercer alias, ya que el primer alias agrega esa opción ls.
Mikel
1
@ Mikel whoa, no me di cuenta de que aliasera recursivo. Eso me permite hacer el ejemplo mucho más simple.
Michael Kropat
Mucho mejor. :-)
Mikel
0

No es una respuesta directa a su pregunta, pero tengo scripts de contenedor para manejar cosas como esta en lugar de complicaciones adicionales en el .bashrc Por ejemplo, aquí está mi script l que maneja su caso aquí de una manera multiplataforma:

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

Pádraig Brady
fuente