Negli script di configurazione della shell, come posso spiegare le differenze tra coreutils su BSD rispetto a GNU?


9

Fino a questo mese, le mie configurazioni di shell sono state piuttosto semplici (solo con .bashrco .bash_profilecon alcuni alias principalmente), ma l'ho riformattato in modo da poter ottenere un comportamento diverso a seconda che sto usando zsh e bash. Prima generano un file di configurazione della shell generico che dovrebbe funzionare per qualsiasi cosa, quindi si specializzano per la shell specifica in uso (ho un link simbolico a questo).

Sono stato sorpreso oggi quando ha lssmesso di funzionare. Si è scoperto che durante il refactoring .bashrc, c'era un alias

alias ls='ls --color=always'

quello stava rompendo le cose per lsin bash sul terminale in OSX. Una volta ho visto che a BSD lspiace il -Gcolore, ma a GNU (o qualunque cosa fosse su Ubuntu) --color, è stato chiaro che alcune opzioni differiscono.

La mia domanda è: qual è il modo migliore per spiegare le differenze nelle opzioni e simili tra coreutils BSD e GNU? Devo testare una variabile env in ifblocchi per vedere quale sistema operativo viene utilizzato e applicare il comportamento corretto? Oppure ha più senso creare file di configurazione separati per ciascun sistema operativo?

Sebbene le risposte a queste domande possano essere soggettive, sembra che una riduzione del campo di applicazione delle differenze tra coreutils di BSD e GNU e le strategie per aggirarle per rendere una configurazione generica utilizzabile sulla maggior parte dei * nix sarebbe abbastanza oggettiva.


Cambiare shell non risolverà nulla ed ls -cè diverso da ls --color. Modificata la tua domanda da correggere.
Mikel,

Risposte:


9

L'unico modo affidabile per scrivere script che supportano diversi sistemi operativi è utilizzare solo le funzionalità definite da POSIX.

Per cose come le configurazioni personali della shell, puoi usare hack adatti al tuo caso d'uso specifico. Qualcosa come il seguente è brutto, ma raggiungerà l'obiettivo.

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

Ho giocato con diversi metodi e penso che la tua soluzione "brutta" sia abbastanza buona e nemmeno così brutta. A quanto pare, non avevo notato la discrepanza nelle opzioni per ls prima perché stavo usando GNU coreutils da Ports. Questo è un esempio del perché fare un 'if' su $ OSTYPE non riesce a fornire i risultati desiderati.
labirinto il

C'è un modo per sopprimere l'errore che proviene da "if ls --version" quando i coreutils GNU non sono presenti (ma sono ancora in grado di testare i coreutils)?
labirinto,

Oh, non importa di sopprimere l'errore. Ho semplicemente reindirizzato stderr su / dev / null prima di eseguire il piping su grep e funziona come vorrei.
labirinto

3
Invece di cercare coreutilsesplicitamente, perché non provare semplicemente se la bandiera colorata funziona, ad es if ls --color=auto -d / >/dev/null 2>&1; then ....
Mikel,

@mikel se ti preoccupi solo del colore (come nell'esempio), va bene. Se ti interessano anche altre funzionalità, è utile verificare la presenza di coreutils.
Giordania,

3

Spargere il codice con ifistruzioni per eseguire uno switch sul tipo di coreutils funziona, tuttavia la soluzione di programmazione pulita per la gestione di tipi diversi consiste nell'utilizzare il polimorfismo . Dato che questo è Bash, non abbiamo un polimorfismo in sé, ma ho fatto un casino per falsificarlo. L'unico requisito è che il tuo .bashrcfile, ecc. Sia organizzato in funzioni.

Per prima cosa creo un test per il tipo di piattaforma coreutils :

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

Quindi possiamo spedire in base al tipo:

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

Ecco l' implementazione di BSD :

define_standard_aliases_bsd() {
    define_standard_aliases
}

configure_shell_vars_bsd() {
    configure_shell_vars
    export CLICOLOR=1
}

(Nota che usiamo la CLICOLORvariabile per attivare i colori invece di usare un alias, che sembra un pulitore più piccolo)

E l' impelementazione GNU :

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

configure_shell_vars_gnu() {
    configure_shell_vars
}

Per completezza, ecco un esempio di implementazione della "base astratta":

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

configure_shell_vars() {
    export EDITOR=vim
}

Questo è molto più pulito, a meno che tu non sia sullo 0,1% dei sistemi con ad esempio GNU ls ma non GNU cat installato (forse è davvero vecchio e hanno fileutils ma non textutils). Sarei tentato di usarlo lsnel tuo dispatcher piuttosto che cat, soprattutto perché nessuno dei tuoi alias coinvolge cat.
Mikel,

Inoltre, non dovresti aver bisogno --color=autodel tuo secondo e terzo alias, poiché il primo alias aggiunge questa opzione a ls.
Mikel

1
@Mikel whoa, non mi ero reso conto che aliasfosse ricorsivo. Questo mi permette di rendere l'esempio molto più semplice.
Michael Kropat,

Molto meglio. :-)
Mikel

0

Non è una risposta diretta alla tua domanda, ma ho script wrapper per gestire cose come questa piuttosto che complicazioni extra nel .bashrc Ad esempio ecco il mio script che gestisce il tuo caso qui in modo multipiattaforma:

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.