Atualizando o Bash no macOS

Daniel Weibel Blocked Unblock Seguir Seguindo 13 de janeiro

Uma coisa que muitos usuários do macOS não sabem é que estão usando uma versão completamente desatualizada do shell Bash. No entanto, é altamente recomendável usar uma versão mais recente do Bash no macOS, pois ele permite que você use novos recursos úteis. Este artigo explica como fazer isso.

Versão padrão de bash no macOS

Para ver como está desatualizada a versão do Bash incluída no macOS, execute o seguinte comando:

 $ bash --version 
GNU bash, versão 3.2.57 (1) -release (x86_64-apple-darwin18)
Direitos autorais (C) 2007 Free Software Foundation, Inc.

Como você pode ver, esta é a versão 3.2 do GNU Bash , que data de 2007 ! Esta versão do Bash está incluída em todas as versões do macOS, mesmo as mais recentes.

A razão pela qual a Apple inclui uma versão antiga do Bash em seu sistema operacional tem a ver com o licenciamento . Desde a versão 4.0 (sucessora do 3.2), o Bash usa a Licença Pública Geral GNU v3 (GPLv3) , que a Apple não suporta (quer). Você pode encontrar algumas discussões sobre isso aqui . A versão 3.2 do GNU Bash é a última versão com uma licença que a Apple está disposta a aceitar, e por isso continua.

Isso significa que o mundo inteiro (por exemplo, Linux) continua com novas versões do Bash, enquanto os usuários do macOS estão presos a uma versão antiga de uma década atrás. No momento desta publicação, a versão mais recente do GNU Bash é 5.0 (veja aqui ), que foi lançada em janeiro de 2019. Neste artigo, eu dou instruções para atualizar o shell padrão do seu sistema para a versão mais nova do Bash.

Por que atualizar?

Mas por que se preocupar em obter uma versão mais nova se o Bash 3.2 funciona bem? A principal razão, para mim, pessoalmente, é a conclusão programável . Esse é o recurso que permite digitar um comando, nome de arquivo, variável ou qualquer outro token de token parcialmente e, em seguida, pressionar Tab para concluí-lo automaticamente (ou pressione Tab duas vezes para exibir uma lista de todas as correspondências possíveis).

Conclusão programável existe em Bash 3.2, e você certamente usá-lo muito para comandos e nomes de arquivos-completar de automóveis. No entanto, o que muitos usuários do macOS não sabem é que ele também permite conclusões específicas de comandos, o que significa que você pode concluir automaticamente os subcomandos, opções e argumentos específicos do comando. Imagine, por exemplo, que você digite cmd -[tab][tab] e você instantaneamente obterá uma lista de todas as opções aplicáveis. Soa útil, certo?

Isso é possível graças aos scripts de conclusão fornecidos pelos comandos individuais. Os comportamentos de conclusão podem ser tão sofisticados quanto os scripts de conclusão que os definem.

O problema é que os recursos de conclusão programáveis do Bash foram estendidos desde a versão 3.2, e a maioria dos scripts de conclusão usa esses novos recursos. Isso significa que esses scripts de conclusão não funcionarão com o Bash 3.2 e, portanto, você não pode usar a funcionalidade de conclusão fornecida por esses comandos com o Bash 3.2 (por exemplo, os scripts de conclusão do docker e do kubectl simplesmente não funcionam com o Bash 3.2).

Usando uma versão mais nova do Bash, você pode configurar o preenchimento automático desses comandos, o que pode ser extremamente útil. Vou discutir em um artigo de acompanhamento como usar o preenchimento automático específico do comando com o Bash no macOS.

Como atualizar?

Para atualizar o shell padrão do seu sistema macOS para a versão mais recente do Bash, você precisa fazer três coisas:

  1. Instale a última versão do Bash
  2. "Bash Whitelist" novo como um shell de login
  3. Definir novo Bash como o shell padrão

Cada etapa é extremamente fácil, conforme explicado a seguir.

Nota: as instruções a seguir não alteram a versão antiga do Bash, mas instalam uma nova versão e a definem como padrão. As duas versões existirão lado a lado no seu sistema, mas você pode simplesmente ignorar a versão antiga a partir daí.

Instalar

Eu recomendo usar o Homebrew para instalar a última versão do Bash:

 brew install bash 

Já é isso!

Para verificar a instalação, você pode verificar se agora tem duas versões do Bash no seu sistema:

 $ -que é uma festa 
/ usr / local / bin / bash
/ bin / bash

O primeiro é a nova versão e o segundo é a versão antiga:

 $ / usr / local / bin / bash --version 
GNU bash, versão 5.0.0 (1) -release (x86_64-apple-darwin18.2.0)
Direitos autorais (C) 2019 Free Software Foundation, Inc.
Licença GPLv3 +: GNU GPL versão 3 ou posterior < http://gnu.org/licenses/gpl.html >
 Isto é software livre; você é livre para mudar e redistribuí-lo. 
NÃO HÁ NENHUMA GARANTIA, na medida permitida por lei.
 $ / bin / bash --version 
GNU bash, versão 3.2.57 (1) -release (x86_64-apple-darwin18)
Direitos autorais (C) 2007 Free Software Foundation, Inc.

Como o diretório da nova versão ( /usr/local/bin ) vem por padrão antes do diretório da versão antiga ( /bin ) na variável PATH , a versão usada quando você acabou de digitar bash é a nova:

 $ bash --version 
GNU bash, versão 5.0.0 (1) -release (x86_64-apple-darwin18.2.0)
...

Por enquanto, tudo bem. Agora você fez desta versão o padrão.

Whitelist

O UNIX inclui um recurso de segurança que restringe os shells que podem ser usados como shells de login (ou seja, o shell usado após o login no sistema) para uma lista de shells “confiáveis”. Essas shells estão listadas no arquivo /etc/shells .

Como você deseja usar o shell Bash recém-instalado como o shell padrão, ele deve ser capaz de atuar como um shell de login. Isso significa que você precisa adicioná-lo ao arquivo /etc/shells . Você pode editar este arquivo como o usuário root:

 $ sudo vim / etc / shells 

E adicione o shell /usr/local/bin/bash ao seu conteúdo, para que o arquivo se pareça com isto:

 / bin / bash 
/ bin / csh
/ bin / ksh
/ bin / sh
/ bin / tcsh
/ bin / zsh
/ usr / local / bin / bash

É isso para este passo!

Definir o shell padrão

Neste ponto, se você abrisse uma nova janela de terminal, ainda estaria usando o Bash 3.2. Isso ocorre porque /bin/bash ainda está definido como o shell padrão. Para mudar isso para o seu novo shell, execute o seguinte comando:

 $ chsh -s / usr / local / bin / bash 

É isso aí! O shell padrão para seu usuário atual agora está configurado para a nova versão do Bash. Se você fechar e reabrir a janela do terminal, você já deve estar usando a nova versão. Você pode verificar isso da seguinte maneira:

 $ echo $ BASH_VERSION 
5.0.0 (1) -release

O comando chsh altera o shell padrão apenas para o usuário que executa o comando. Se você quiser alterar o shell padrão para outros usuários também, você pode repetir esse comando assumindo a identidade de outro usuário (por exemplo, com su ). O mais importante talvez você queira alterar o shell padrão do usuário root, que pode ser feito da seguinte maneira:

 $ sudo chsh -s / usr / local / bin / bash 

Dessa forma, se você usar o sudo su para abrir um shell como o usuário root, ele também usará a nova versão do Bash.

Anotações importantes

Uso em scripts

Como mencionado, você não alterou a versão padrão do Bash, mas instalou uma nova versão e a definiu como padrão. As duas versões do Bash existem lado a lado no seu sistema:

  • /bin/bash : versão antiga
  • /usr/local/bin/bash : nova versão

Nos scripts de shell, você geralmente tem uma linha shebang , como no script a seguir:

 #! / bin / bash 
echo $ BASH_VERSION

É importante notar que esta linha shebang refere-se explicitamente à versão antiga do Bash (já que especifica /bin/bash ). Isto significa que se você executar este script, ele será interpretado pela versão antiga do Bash (você pode vê-lo na saída do script, que será algo como 3.2.57(1)-release ).

Na maioria dos casos, isso provavelmente não é um problema. Mas se você quisesse que seu script fosse explicitamente interpretado pela nova versão do Bash, você poderia mudar a linha shebang assim:

 #! / usr / local / bin / bash 
echo $ BASH_VERSION

Agora a saída será algo como 5.0.0(1)-release . No entanto, observe que essa solução não é portátil , o que significa que provavelmente não funcionará em outros sistemas. Isto porque, outros sistemas provavelmente não terão um shell localizado em /usr/local/bin/bash (considerando que /bin/bash é quase um padrão).

Para combinar o melhor dos dois mundos, você pode usar a seguinte linha da shebang:

 #! / usr / bin / env bash 
echo $ BASH_VERSION

Este é um formato recomendado para uma linha shebang. Ele funciona inspecionando o PATH e usando o primeiro executável bash encontrado como o interpretador do script. Se o diretório da nova versão está localizado antes do diretório da versão antiga no PATH (que é o padrão), então a nova versão será usada, e a saída do script será algo como 5.0.0(1)-release .

Por N ot Symlink?

Em vez de lidar com ambas as versões do Bash, você não poderia simplesmente excluir a versão antiga e colocar a nova versão em seu lugar? Por exemplo, criando um link simbólico em /bin/bash que aponta para a nova versão, como o seguinte?

 $ sudo rm / bin / bash 
$ sudo ln / usr / local / bin / bash / bin / bash

Desta forma, mesmo scripts com um #!/bin/bash seriam interpretados pela nova versão do Bash, então por que não fazer isso?

Você pode fazer isso, mas precisa contornar um recurso de segurança do macOS chamado System Integrity Protection (SIP). ( Wikipedia ) Esse recurso proíbe o acesso de gravação a determinados diretórios até mesmo para o usuário raiz (é por isso que ele também é chamado de "sem raiz"). Esses diretórios estão listados aqui e incluem /bin . Isso significa que, mesmo como usuário root, você não pode executar os comandos acima, porque você não tem permissão para excluir nada ou criar nenhum arquivo em /bin .

A maneira de contornar isso é desabilitar o SIP, fazer as alterações em /bin e habilitar o SIP novamente. Ativar e desativar o SIP pode ser feito de acordo com as instruções aqui . Ele requer que você inicialize sua máquina no modo de recuperação e use os csrutil disable e csrutil enable . Cabe a você se você quiser passar por este incômodo para substituir completamente a versão antiga do Bash, ou se você está satisfeito com as duas versões do Bash vivendo lado a lado.

Referências