Introdução
O @Dio lançou um vídeo sobre como ele fez o dele mas como ele não é programador o script ficou bem complicado de manter além de ter alguns problemas mais “técnicos” que eu prometo que não vou encher falando sobre, o script vai ser feito linha a linha então mesmo que você nunca tenha feito um shell script você vai conseguir compreender, então como disse o filósofo Mario Mario: let’s go!
Ah, esse artigo vai ser praticamente um mini e-book, sugiro favoritar ele e é claro que o script completo vai estar no final do artigo
Criando o Script
O script terá como base o script do dio não terá todos os pacotes mas o objetivo é só pra “pegar o felling” e você fazer o seu, tendo isso em mente vamos pro primeiro passo (e mais importante)
1. Shebang
Ao contrário do que muita gente pensa, “shell script” não é uma linguagem mas sim um conjunto de linguagens de programação interpretadas, por tanto você precisa dizer pro sistema quem você quer que interprete o seu script (sim, é como uma peça de teatro mesmo), e isso é feito através de uma linha começando com #!
seguido da localização do interpretador, esse #!
chama “shebang”, muita gente (inclusive o Dio), usa a linha assim:
#!/bin/bash
Mas isso está errado, ao contrário da crença popular, o bash não precisa estar em /bin, ele pode estar em qualquer lugar que o sistema consiga carregar os executáveis, mas como evitar problemas quanto a isso? É bem simples, vamos perguntar ao sistema onde o bash está, o executável que faz isso é o env
e o legal dele é que ele sempre fica em /usr/bin, então nossa primeira linha fica:
#!/usr/bin/env bash
Dica para Python: ao procurar o python pelo env você garante que o seu sistema consiga encontrar a versão correta exata do python
2. Saia ao primeiro erro
Uma coisa importante nesse tipo de script é que se um comando der erro, provavelmente seu setup vai ficar incompleto e você pode literalmente quebrar o sistema, felizmente o bash traz um meio bem simples de corrigir isso, simplesmente adicione a próxima linha:
set -e
Essa foi a nossa segunda linha
3. O que o script vai instalar?
Aqui nós vamos para a segunda parte mais importante, é a parte que não é relacionada com shell script em si (totalmente) mas vai definir todo o resto daqui pra frente, nós já definimos o objetivo que é instalar pacotes e repositórios agora precisamos definir quais deles vão ser instalados, para isso nós vamos usar um tipo especial de variável chamada de “array” ou arranjo, ela permite que você adicione mais de um valor ao mesmo tempo, pense nelas como uma gaveta onde você pode colocar várias coisas e pegar depois, um array funciona assim no seu uso mais básico (e o que interessa pra gente):
nome_do_array=( valor1 valor2 valor2 ultimo_valor )
Note que os valores são separados por espaço, a lista está entre parenteses, o sinal de igual está logo depois do nome do array e o “abre parenteses” está logo depois do sinal de igual, isso é muito importante, agora vamos a um exemplo real, mas antes um aviso amigável:
Nota: O objetivo é que você aprenda a fazer o seu script então, vou colocar apenas alguns exemplo, troque pelos seus pacotes
Vamos começar com os pacotes “normais” do APT, precisamos de um nome que seja fácil de identificar, “pacotes_apt” parece bom não acha? E também precisamos da lista de pacotes, para exemplificar vou usar esses: winff (Um conversor de vídeos), guvcview (um app pra webcam), virtualbox (um virtualizador de sistemas operacionais) e o piper (um app para configurar mouses da Logitech), então nossa linha fica assim:
pacotes_apt=(winff guvcview virtualbox piper)
Simples assim, mas e se o meio de instalação for diferente? Por exemplo você quer que os pacotes tenham os pacotes recomendados? A logica é a mesma, você só precisa de um array diferente:
pacotes_apt_recomendados=(winehq-stable wine-stable wine-stable-i386 wine-stable-amd64)
Pegou a ideia? Isso vale também para PPAs, Snaps e qualquer outra coisa, exemplo de PPAs:
ppas=(graphics-drivers/ppa libratbag-piper/piper-libratbag-git)
Você deve ter sentido falta do “ppa:”, calma, ele não é necessário na lista, ele vai ser adicionado mais pra frente. Nesse momento você deve estar perguntando, mas e se eu quise adicionar aldo co espaços? Simples, coloque o valor entre aspas duplas com aspas simples assim:
repos=("deb https://dl.winehq.org/wine-builds/ubuntu/ bionic main")
Se você quiser legibilidade e itens longos você pode colocar cada um em uma linha, por exemlo, vamos colocar links baixar alguns arquivos:
downloads=(
"https://github.com/Automattic/simplenote-electron/releases/download/v1.8.0/Simplenote-linux-1.8.0-i386.AppImage"
"https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb"
"https://dl.winehq.org/wine-builds/winehq.key "
)
Nota: por motivos de boas praticas (como evitar o bash interpretar o caractere & em algumas URLs) sempre coloque links entre aspas, mesmo se não tiver espaços
Como você percebeu o separador de itens pode ser tanto espaço como quebra de linha (Enter). Agora que deu pra pegar a lógica vamos as linhas que vamos adicionar:
repositorios=("deb https://dl.winehq.org/wine-builds/ubuntu/ bionic main")
ppas=(graphics-drivers/ppa libratbag-piper/piper-libratbag-git)
downloads=(
"https://github.com/sudo-give-me-coffee/PhotoGIMP/releases/download/continuous/PhotoGIMP-x86_64.AppImage"
"https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb"
"https://dl.winehq.org/wine-builds/winehq.key"
)
pacotes_apt=(winff guvcview virtualbox piper)
pacotes_apt_recomendados=(winehq-stable wine-stable wine-stable-i386 wine-stable-amd64)
libs_32bits=(gnutls30 ldap-2.4-2 gpg-error0 xml2 asound2-plugins sdl2-2.0-0 freetype6 dbus-1-3 sqlite3-0)
snaps=(spotify nextcloud)
snaps_classic=(slack skype)
chaves=(winehq.key)
Pra exemplo tá de bom tamanho, se você reparar bem eu tirei “lib” e “:i386” dos itens dos arrays, como eles estão na mesma linha (separados por espaço) e todos os itens tem em comum, não é necessário adicionar no array, faremos isso via programação! Vamos ao próximo passo.
3. Crie seu diretório de trabalho
Sempre que você vai trabalhar com pós instalação, é comum você baixar arquivos, você não está afim de entupir a sua home de arquivos né? Pensando nesse tipo de situação, foi criada a ferramenta “mktemp” ela cria diretórios e arquivos temporários únicos para o seu script e imprime o local onde foram criados, como a gente vai baixar arquivos nós vamos pedir um diretório e já entrar nele, á próxima linha que vamos adicionar ao script é:
cd $(mktemp -d)
O que significa isso? bem o “cd” vem de “change directory” ou seja, ele muda o diretório de trabalho, o “mktemp” é a ferramenta que eu falei, e o $( e ), está dizendo pro bash:
pegue a saída da linha de comando que está entre ( e ). Ou seja essa linha significa:
Pegue a saída do comando “mktemp -d” e passe para o “cd”.
Tudo certo até aqui? Bora pro próximo…
4. Pegando todos os valores de um array e usando pipelines
Essa seção é meramente explicativa, não adiciona nenhuma linha ao script
O Bash permite que todos os itens de um array sejam transformados em uma linha de itens separados por espaços a sintaxe pra isso é essa:
${nome_do_array[@]}
Nós vamos usar isso aliado ao pipelines quando precisarmos formatar a saída, pipelines nada mais são que passar a saída de um comando para outro, nesse processo se usa um caractere chamado pipe (|) e os comandos podem ser escritos numa linha só dai o nome pipeline, por exemplo, se você quer que a saída do “comando 1” seja redirecionado para o “comando 2” você pode fazer assim:
comando 1 | comando 2
Você pode seguenciar quantos comandos quiser assim, agora vamos voltar para a prática
5. Baixando arquivos necessários (pacotes, AppImages, chaves…)
A primeira coisa que vamos fazer é baixar os arquivos isso é feito através da ferramenta “wget” que vem de “web get” ou “pegar da web”, nós vamos usar duas “flags” pra melhorar a visualização do script, são elas -nv que remove saídas de texto desnecessárias e -c que permite continuar de onde paramos, os links que vamos usar estão no array “downloads” nossa próxima linha vai ser essa:
wget -nv -c ${downloads[@]}
Simples assim, agora todos os arquivos serão baixados em sequência
6. Adicione as chaves dos repositórios extras
Na maioria das vezes os repositórios pedem uma chave para serem utilizados, nós baixamos no passo anterior mas elas não estão no sistema, nós podemos adicionar elas com o “apt-key” assim:
apt-key add [lista de arquivos]
A lógica que vamos usar é a mesma do passo anterior, então a próxima linha adicionada será:
apt-key add ${chaves[@]}
7. Adicionando suporte a 32 bits
Se você deseja usar aplicativos 32 bits você precisa ativar o suporte a essa arquitetura as próximas linhas fazem isso, então adicionamos elas ao script:
dpkg --add-architecture i386
apt update
Note que tem um “apt update” no final, ele é extremamente importante, sem ele pacotes 32 bits de outros repositórios podem não funcionar
8. Laço for
Existem casos onde o comando só aceita um item por vez, nesse caso passar ${nome_do_array[@]} vai dar problema, mas como corrigir? Não pode ser complicado, nós vamos executar o comando para cada item no array, parece difícil, mas é simples:
for item in ${array[@]}; do
comando "$item"
done
Um exemplo é o “add-repository” você só pode carregar um por vez as próximas linhas fazem isso:
for repositorio in ${repositorios[@]};; do
apt-add-repository "$repositorio" -y
done
Simples assim, as 3 linhas acima vão pro nosso script
9. PPAs
Se você reparoubem lá no começo nós retiramos o “ppa:” do inicio dos nomes do PPAs, agora a gente vai adicionar elas, vale lembrar que ppas são repositórios então nós precisamos do laço for, por hora vamos apenas estruturar:
for ppa in ${ppas[@]}; do
done
Para adicionar o ppa: na frente basta dar um echo “ppa:”$ppa, o nosso parâmetro fica assim:
for ppa in ${ppas[@]}; do
apt-add-repository "ppa:"$ppa -y
done
10. Atualizando os repositórios
Após adicionar os repositórios nós precisamos dizer pro APT que nós fizemos isso, para isso a próxima linha do nosso script faz isso:
apt update
Ok, com o sistema configurado vamos finalmente começar a fazer algo visível
11. Instalando os programas do repositório
Até aqui seu sistema vai ser configurado para receber programas mas não recebeu nenhum (tirando eventuais AppImages baixados) aqui começa o fim do script porque nós finalmente vamos instalar os programas, primeiro os que podem ser instalados sem precisar formatar o nome, as próximas linhas vão ser adicionadas:
apt install "snapd" ${pacotes_apt[@]} -y
apt install --install-recommends ${pacotes_apt_recomendados[@]} -y
snap install ${snaps[@]}
snap install --classic ${snaps_classic[@]}
Muito fácil né? Agora complica um pouquinho, porque os próximos pacotes a serem instalados precisam ser formatados, ou seja adicionado texto antes e depois, apesar de ser simples, pode parecer um tanto complexo a primeira vista, pode ser feito assim:
echo "${libs_32bits[@]}" | tr ' ' '\n' | awk '{print "lib"$1":i386"}' | tr '\n' ' '
Mas calma que eu vou explicar por partes:
echo "${libs_32bits[@]}"
Serve pra imprimir todos os itens do array separados por espaços
tr ' ' '\n'
Traduz espaços ' '
para quebras de linha '\n'
awk '{print "lib"$1":i386"}'
Eé um script awk que imprime (print
) o primeiro item de cada linha ($1
) adicionando um texto antes ("lib"
) e depois (":i386"
)
tr '\n' ' '
Traduz quebras de linha '\n'
para espaços ' '
Sabendo disso podemos adicionar a próxima linha do script:
sudo apt install $(echo "${libs_32bits[@]}" | tr ' ' '\n' | awk '{print "lib"$1":i386"}' | tr '\n' ' ')
Agora falta apenas os programas de fora do repositório
12. Programas de fora do repositório (.deb)
Você pode instalar os programas de fora do repositórios de forma automatizada também, no caso dos . debs e considerando que você baixou pelo script você pode colocar essa linha:
apt install ./*.deb
13. Programas de fora do repositório (.AppImage)
Os AppImages podem ser “instalados” no sistema também, primeiro você precisa criar uma pasta na sua home para eles, pra isso a próxima linha resolve:
mkdir $HOME/Applications
Dica: O bash substitui $HOME com o caminho para a sua home automaticamente
Agora movemos os AppImages pra lá:
mv *.AppImages $HOME/Applications
Por fim damos permissão para o seu usuário para a sua pasta e os AppImages:
chmod 777 -r $HOME/Applications/
Agora instalamos o AppImageD ele vai adicionar os AppImages no menu de apps automaticamente:
wget "https://github.com/AppImage/appimaged/releases/download/continuous/appimaged-x86_64.AppImage"
chmod +x appimaged-x86_64.AppImage
./appimaged-x86_64.AppImage --install
14. O script completo:
#!/usr/bin/env bash
set -e
# Aqui começam as configurações do script
repositorios=("deb https://dl.winehq.org/wine-builds/ubuntu/ bionic main")
ppas=(graphics-drivers/ppa libratbag-piper/piper-libratbag-git)
downloads=(
"https://github.com/sudo-give-me-coffee/PhotoGIMP/releases/download/continuous/PhotoGIMP-x86_64.AppImage"
"https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb"
"https://dl.winehq.org/wine-builds/winehq.key"
)
pacotes_apt=(winff guvcview virtualbox piper)
pacotes_apt_recomendados=(winehq-stable wine-stable wine-stable-i386 wine-stable-amd64)
libs_32bits=(gnutls30 ldap-2.4-2 gpg-error0 xml2 asound2-plugins sdl2-2.0-0 freetype6 dbus-1-3 sqlite3-0)
snaps=(spotify nextcloud)
snaps_classic=(slack skype)
chaves=(winehq.key)
# A partir daqui o script irá trabalhar com as configurações
cd $(mktemp -d)
wget -nv -c ${downloads[@]}
apt-key add ${chaves[@]}
dpkg --add-architecture i386
apt update
for repositorio in ${repositorios[@]};; do
apt-add-repository "$repositorio" -y
done
for ppa in ${ppas[@]}; do
apt-add-repository "ppa:"$ppa -y
done
apt update
apt install "snapd" ${pacotes_apt[@]} -y
apt install --install-recommends ${pacotes_apt_recomendados[@]} -y
sudo apt install $(echo "${libs_32bits[@]}" | tr ' ' '\n' | awk '{print "lib"$1":i386"}' | tr '\n' ' ')
snap install ${snaps[@]}
snap install --classic ${snaps_classic[@]}
apt install ./*.deb
mkdir $HOME/Applications
chmod 777 -r $HOME/Applications/
wget "https://github.com/AppImage/appimaged/releases/download/continuous/appimaged-x86_64.AppImage"
chmod +x appimaged-x86_64.AppImage
./appimaged-x86_64.AppImage --install
apt dist-upgrade -y
apt autoclean
echo "Chegamos ao final"
Conclusão
Por mais simples e otimizado que esse script esteja ele não esá completo, agora é a sua vez de fazer, algumas sugestões:
- Pacotes que NÃO instalam dependências recomendadas (só retirar o --install-recommend não resolve
- Suporte a Flatpaks
- Suporte a função remover pacotes