Nos scripts de configuração do shell, como posso explicar as diferenças entre os coreutils no BSD em comparação com o GNU?

9

Até este mês, minhas configurações de shell eram bastante simples ( principalmente com .bashrcou .bash_profilecom alguns aliases), mas eu a refatorava para que eu pudesse ter um comportamento diferente, dependendo de estar usando zsh e bash. Eles primeiro fornecem um arquivo de configuração de shell genérico que deve funcionar para qualquer coisa, depois se especializam para o shell específico que está sendo usado (eu ligo para isso).

Fiquei surpreso hoje quando lsparei de trabalhar. Verificou-se que durante a refatoração .bashrchavia um apelido

alias ls='ls --color=always'

que estava quebrando coisas lsno bash no Terminal no OSX. Quando vi que o BSD lsgosta -Gde cores, mas o GNU (ou o que quer que estivesse no Ubuntu) gosta --color, ficou claro que muitas opções diferem.

Minha pergunta é: qual é a melhor maneira de explicar as diferenças de opções entre os coreutils do BSD e do GNU? Devo testar uma variável env em ifblocos para ver qual sistema operacional está sendo usado e aplicar o comportamento correto? Ou faz mais sentido criar arquivos de configuração separados para cada sistema operacional?

Embora as respostas a essas perguntas possam ser subjetivas, parece um resumo do escopo das diferenças entre os coreutils do BSD e do GNU e as estratégias para contorná-las para tornar uma configuração genérica utilizável na maioria dos * nix seriam bastante objetivas.

labirinto
fonte
Mudar conchas não conserta nada e ls -cé diferente de ls --color. Editou sua pergunta para corrigir.
Mikel

Respostas:

9

A única maneira confiável de escrever scripts que suportam sistemas operacionais diferentes é usar apenas os recursos definidos pelo POSIX.

Para coisas como suas configurações pessoais de shell, você pode usar hacks adequados ao seu caso de uso específico. Algo como o seguinte é feio, mas alcançará o objetivo.

if ls --version 2>/dev/null | grep -q 'coreutils'; then
    alias ls='ls --color=always'
else
    alias ls='ls -G'
fi
jordanm
fonte
Venho brincando com métodos diferentes e acho que sua solução "feia" é muito boa e nem tão feia. Acontece que eu não havia notado a incompatibilidade nas opções do ls anteriormente porque estava usando o GNU coreutils do Ports. Este é um exemplo de por que fazer um 'se' em $ OSTYPE pode falhar na entrega dos resultados desejados.
labirinto
Existe uma maneira de suprimir o erro resultante de "if ls --version" quando os coreutils do GNU não estão presentes (mas ainda é possível testar os coreutils)?
labirinto
Oh, não se esqueça de suprimir o erro. Acabo de redirecionar o stderr para / dev / null antes de enviar para o grep e funciona como eu gostaria.
labirinto
3
Em vez de procurar coreutilsexplicitamente, por que não testar apenas se a bandeira de cores funciona, por exemplo if ls --color=auto -d / >/dev/null 2>&1; then ....
22614 Mikel
@ Mikel Se você está preocupado apenas com cores (como no exemplo), tudo bem. Se você se preocupa com outros recursos também, é útil procurar por coreutils.
Jordanm
3

Sujar o código com ifinstruções para executar uma alternância no tipo de coreutils funciona, no entanto, a solução de programação limpa para lidar com diferentes tipos é usar o polimorfismo . Como esse é o Bash, não temos polimorfismo em si, mas tenho andado brincando com uma maneira de falsificá-lo. O único requisito é que seu .bashrcarquivo etc. seja organizado em funções.

Primeiro, crio um teste para o 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
}

Em seguida, podemos despachar com base no tipo:

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

Aqui está a implementação do BSD :

define_standard_aliases_bsd() {
    define_standard_aliases
}

configure_shell_vars_bsd() {
    configure_shell_vars
    export CLICOLOR=1
}

(Observe que usamos a CLICOLORvariável para ativar as cores em vez de usar um alias, que parece um limpador menor)

E a impelementação GNU :

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

configure_shell_vars_gnu() {
    configure_shell_vars
}

Para completar, aqui está uma implementação de exemplo da "base abstrata":

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

configure_shell_vars() {
    export EDITOR=vim
}
Michael Kropat
fonte
Isso é muito mais limpo, a menos que você esteja nos 0,1% dos sistemas com, por exemplo, GNU ls, mas não o GNU cat instalado (talvez seja realmente antigo e eles tenham arquivos de arquivos, mas não textos). Eu ficaria tentado a usar o lsseu expedidor em vez de cat, especialmente porque nenhum dos seus pseudônimos envolve cat.
Mikel
Além disso, você não deve precisar --color=autodo seu segundo e terceiro aliases, pois o primeiro alias adiciona essa opção a ls.
Mikel
1
@ Mikel whoa, eu totalmente não sabia que aliasera recursivo. Isso me permite tornar o exemplo muito mais simples.
Michael Kropat
Muito melhor. :-)
Mikel
0

Não é uma resposta direta à sua pergunta, mas eu tenho scripts de wrapper para lidar com coisas assim, em vez de complicação extra no .bashrc. Por exemplo, aqui está o meu script l que lida com o seu caso aqui de uma maneira multiplataforma:

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

Pádraig Brady
fonte