Wie kann ich in Shell-Konfigurationsskripten Unterschiede zwischen Coreutils auf BSD und GNU berücksichtigen?

9

Bis zu diesem Monat waren meine Shell-Konfigurationen ziemlich einfach (nur ein .bashrcoder .bash_profilehauptsächlich mit einigen Aliasnamen), aber ich habe sie überarbeitet, damit ich je nach Verwendung von zsh und bash ein anderes Verhalten erhalten kann. Sie geben zuerst eine generische Shell-Konfigurationsdatei heraus, die für alles funktionieren soll, und spezialisieren sich dann auf die verwendete Shell (ich verweise darauf).

Ich war heute überrascht, als ich lsaufhörte zu arbeiten. Es stellte sich heraus, dass es beim Refactoring .bashrceinen Alias ​​gab

alias ls='ls --color=always'

Das war der Grund für die lsBash auf dem Terminal in OSX. Als ich sah, dass BSD Farbe lsmag -G, GNU (oder was auch immer auf Ubuntu war) mag --color, war klar, dass sich einige Optionen unterscheiden.

Meine Frage ist, wie können Unterschiede in den Optionen und dergleichen zwischen BSD- und GNU-Coreutils am besten berücksichtigt werden. Sollte ich in ifBlöcken nach einer env-Variablen suchen, um festzustellen, welches Betriebssystem verwendet wird, und das richtige Verhalten anwenden? Oder ist es sinnvoller, für jedes Betriebssystem separate Konfigurationsdateien zu erstellen?

Während die Antworten auf diese Fragen subjektiv sein können, scheint es ziemlich objektiv zu sein, den Umfang der Unterschiede zwischen BSD- und GNU-Coreutils und Strategien, um diese zu umgehen, um eine generische Konfiguration für die meisten * nix-Anwendungen nutzbar zu machen, zusammenzufassen.

Labyrinth
quelle
Das Wechseln der Muscheln behebt nichts und ls -cunterscheidet sich von ls --color. Ihre Frage wurde bearbeitet, um sie zu beheben.
Mikel

Antworten:

9

Die einzige zuverlässige Möglichkeit, Skripte zu schreiben, die verschiedene Betriebssysteme unterstützen, besteht darin, nur Funktionen zu verwenden, die von POSIX definiert werden.

Für Dinge wie Ihre persönlichen Shell-Konfigurationen können Sie Hacks verwenden, die zu Ihrem spezifischen Anwendungsfall passen. So etwas wie das Folgende ist hässlich, wird aber das Ziel erreichen.

if ls --version 2>/dev/null | grep -q 'coreutils'; then
    alias ls='ls --color=always'
else
    alias ls='ls -G'
fi
Jordanm
quelle
Ich habe mit verschiedenen Methoden herumgespielt und ich denke, Ihre "hässliche" Lösung ist ziemlich gut und nicht einmal so hässlich. Wie sich herausstellte, hatte ich die Nichtübereinstimmung der Optionen für ls zuvor nicht bemerkt, da ich GNU-Coreutils von Ports verwendete. Dies ist ein Beispiel dafür, warum ein 'if' für $ OSTYPE nicht zu den gewünschten Ergebnissen führen kann.
Labyrinth
Gibt es eine Möglichkeit, den Fehler zu unterdrücken, der von "if ls --version" herrührt, wenn GNU-Coreutils nicht vorhanden sind (aber dennoch auf Coreutils testen können)?
Labyrinth
Oh, vergiss nicht, den Fehler zu unterdrücken. Ich leite stderr einfach nach / dev / null um, bevor ich zu grep weiterleite, und es funktioniert so, wie ich es möchte.
Labyrinth
3
Anstatt coreutilsexplizit zu suchen , warum nicht einfach testen, ob das Farbflag funktioniert, z if ls --color=auto -d / >/dev/null 2>&1; then ....
Mikel
@mikel Wenn Sie sich nur um Farbe kümmern (wie im Beispiel), ist das in Ordnung. Wenn Sie sich auch für andere Funktionen interessieren, ist es hilfreich, nach Coreutils zu suchen.
Jordanm
3

Das Verunreinigen des Codes mit ifAnweisungen zum Umschalten des Coreutil- Typs funktioniert zwar. Die saubere Programmierlösung für den Umgang mit verschiedenen Typen besteht jedoch darin, Polymorphismus zu verwenden . Da dies Bash ist, haben wir keinen Polymorphismus an sich, aber ich habe herumgespielt, um ihn zu fälschen. Die einzige Voraussetzung ist, dass Ihre .bashrcDatei usw. in Funktionen organisiert ist.

Zuerst erstelle ich einen Test für den Plattformtyp coreutils :

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

Dann können wir basierend auf dem Typ versenden:

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

Hier ist die BSD- Implementierung:

define_standard_aliases_bsd() {
    define_standard_aliases
}

configure_shell_vars_bsd() {
    configure_shell_vars
    export CLICOLOR=1
}

(Beachten Sie, dass wir die CLICOLORVariable verwenden, um Farben aliaseinzuschalten, anstatt eine zu verwenden , was ein wenig sauberer zu sein scheint.)

Und die GNU- Impelementation:

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

configure_shell_vars_gnu() {
    configure_shell_vars
}

Der Vollständigkeit halber hier eine Beispielimplementierung der "abstrakten Basis":

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

configure_shell_vars() {
    export EDITOR=vim
}
Michael Kropat
quelle
Dies ist viel sauberer, es sei denn, Sie befinden sich auf 0,1% der Systeme, auf denen z. B. GNU ls, aber keine GNU cat installiert sind (möglicherweise ist es wirklich alt und sie haben Fileutils, aber keine Textutils). Ich wäre versucht, es lsin Ihrem Dispatcher zu verwenden, anstatt cat, da keiner Ihrer Aliase involviert ist cat.
Mikel
Außerdem sollten Sie --color=autoIhren zweiten und dritten Aliase nicht benötigen , da der erste Alias ​​diese Option hinzufügt ls.
Mikel
1
@Mikel whoa, ich wusste überhaupt nicht, dass aliasdas rekursiv war. Dadurch kann ich das Beispiel viel einfacher machen.
Michael Kropat
Viel besser. :-)
Mikel
0

Keine direkte Antwort auf Ihre Frage, aber ich habe Wrapper-Skripte, um solche Dinge zu behandeln, anstatt zusätzliche Komplikationen in der .bashrc. Zum Beispiel ist hier mein l-Skript, das Ihren Fall hier plattformübergreifend behandelt:

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

Pádraig Brady
quelle