[Bash script] Preciso criar uma função de verificação da distro

Olá, como título já diz, preciso fazer esta função para verificar se a distro é Ubuntu, Debian, OpenSuse, Fedora, Arch etc. A verificação será feita para destinar corretamente a instalação de determinado pacote de software, pois nem toda distro utiliza o APT. O problema é q n tenho a mínima ideia de como fazer tal verificação. Se alguém puder me ajudar, ficarei grato.

1 curtida

Geralmente, o arquivo /etc/os-release traz essas informações.
Seria a questão de ver se, por exemplo, o grep dá algum retorno se caçar o nome da distro no arquivo.


Outra opção é usar o comando which gerenciador_de_pacotes que procura o programa no PATH do usuário e caso não ache dá erro, para isolar distros pelo gerenciador de pacotes e não pelo nome.

2 curtidas

Tentei:
grep -i apt /etc/os-release
Nada foi retornado

Usei:
[ $(which pacman) ] && echo “deu certo” || echo “não deu certo”
[ $(which emerge) ] && echo “deu certo” || echo “não deu certo”
não deu certo
[ $(which dpkg) ] && echo “deu certo” || echo “não deu certo”

O 1º e o 2º retornou "não deu certo (uso BigLinux), já o 3º retornou "deu certo. Ou seja, aparentemente já consegui averiguar qual gerenciador de pacotes é utilizado na distro, só preciso criar um modo de fazer uma averiguação em massa, sem ser um por um.

Ninguém disse que não podia ser python, então… :slight_smile:

 #! /bin/python
import platform

plat = platform.platform()

if "fedora" in plat.lower():
    print("bingo!")

Eu não sei exatamente qual texto é retornada em outras plataformas mas acredito que todas retornam em algum lugar do resultado o nome da distro, obviamente, você pode obter muito mais informações além da distro usando esse package.

Você pode dar um print do retorno para ver o que este método em particular retorna:

image

2 curtidas

Vlw, mas preciso que seja em bash. Agora eu até consigo pensar numa forma de fazê-lo, mas ainda tá complicado.

Algum motivo em particular? Praticamente todas as distros tem, e se você precisar pode integrar a um shell script:

echo `./plat.py`
# 
echo $(./plat.py)

A maior vantagem é a universalidade de usar python.

2 curtidas

O screenFetch faz isso que você deseja, você poderia dar uma olhada lá e ver o que você pode utilizar.

Saudações.

1 curtida

As abordagens apresentadas são difíceis de escalar, e o comando which não está presente em todas as distros (acredite se quiser), uma maneira mais fácil de manter é criar um array associativo e indexar cada gerenciador de pacotes e depois perguntar pro bash se cada um existe (sim, pro bash), se existir ok, defina uma variável pra cada ação e pronto, se não feche o script com um erro:

1.Declare o array associativo:

Arrays associativos precisam ser declarados

declare -A GestoresDePacotes

2. Indexe cada gestor de pacote:

#
# Cada ação deve ser separada por algum caractere que não seja:
#
# * Espaços
# * Hífen (-)
# * Sinal de cifrão ($)
# * Caracteres que o bash usa ($,%,&,(,),!,?...
#
# Eu gosto de usar ; é meio que universal
# 
GestoresDePacotes[apt]="install;remove"
# Sendo assim pra adicionar suporte a outro gestor de pacotes tudo que 
# eu preciso fazer é adicionar uma linha com o seguinte padrão:
# GestoresDePacotes[<gestor de pacote>]="<flag para instalar>;<flag para remover>"

2.1 Exemplo, adicionar suporte ao Arch:

Basta adicionar essa linha abaixo da anterior:

GestoresDePacotes[pacman]="-S;-R"

3. A função que torna isso usável:

function DefineQualGestorDePacotes(){
  # Para cada uma das ferramentas
  for ferramenta in "${!GestoresDePacotes[@]}"; do
    # Verifique se ela existe
    type ${ferramenta} &> /dev/null && {
      # Se existir, pegue as opções,
      local flags=${GestoresDePacotes[$ferramenta]}

      # Separe as flags em variáveis,
      # Aqui fica evidente o porquê a ordem das flags precisa ser igual
      local instalar=$(echo ${flags} | cut -d';' -f1)
      local  remover=$(echo ${flags} | cut -d';' -f2)
      
      # E por fim, armazene cada opção em uma variável
      instalar_pacote="${ferramenta} ${instalar}"
       remover_pacote="${ferramenta} ${instalar}"

      # Saia do laço for e da função
      return 
    }
  done
  # Se nenhum gestor de pacote suportado existir no sistema, mostre essa mensagem:
  echo "Desculpe mas seus sistema não usa um dos gestores de pacote suportados"
  # Termine a execução do script como erro 127
  exit 127
  # O erro 127 indica que o script não conseguiu encontrar o comando, é um padrão
}

Depois que você chamar a função você vai estar com um gestor de pacotes funcional na distro, pra usar, basta substituir apt install por ${instalar_pacote} e apt remove por ${remover_pacote} e assim sucessivamente pra cada flag que você adicionar

Por que assim, ao invés de chamar por cada distro?

Simples, a quantidade de distribuições tende ao infinito, enquanto os gestores de pacotes são relativamente poucos

1 curtida

O uso seria

grep -i Ubuntu /etc/os-release && fazer_coisas_do_ubuntu
grep -i Fedora /etc/os-release && fazer_coisas_do_fedora

O os-release contém informações da distribuição em si, não o gerenciador de pacotes.

Não sei se isso acontece aí, mas escrevi esses comandos no Arch Linux e obtive o seguinte:

$ [ $(which pacman) ] && echo “deu certo” || echo “não deu certo”
“deu certo”
$ [ $(which emerge) ] && echo “deu certo” || echo “não deu certo”
which: no emerge in (/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/lib/jvm/default/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl)
“não deu certo”
$ [ $(which dpkg) ] && echo “deu certo” || echo “não deu certo”
which: no dpkg in (/usr/local/sbin:/usr/local/bin:/usr/bin:/usr/lib/jvm/default/bin:/usr/bin/site_perl:/usr/bin/vendor_perl:/usr/bin/core_perl)
“não deu certo”

Ou seja, mensagens de erro estão vazando para o usuário.
Uma maneira de suprimir essas mensagens de erro seria:
which gerenciador_de_pacotes > /dev/null 2>&1 && echo 'deu certo' || echo 'não deu certo'

Inclusive, evitar o [ $() ] permite você usar o comando type que vem embutido no bash. [ $(type pacman) ] retorna um erro.

1 curtida

Uma demo completa:

#!/usr/bin/env bash
# Algumas distros não colocam o bash em /bin, o Fedora é uma delas salvo engano

declare -A GestoresDePacotes
# Array declarado

GestoresDePacotes[apt]="install;remove" # Debian, Mint, Ubuntu, ElementaryOS...
GestoresDePacotes[dnf]="install;remove" # Fedora, RHEL, CentOS...
GestoresDePacotes[pacman]="-S;-R"       # Arch, Manjaro, Reborn...

# A função que determina qual usar:

function DefineQualGestorDePacotes(){
  # Para cada uma das ferramentas
  for ferramenta in "${!GestoresDePacotes[@]}"; do
    # Verifique se ela existe
    type ${ferramenta} &> /dev/null && {
      # Se existir, pegue as opções,
      local flags=${GestoresDePacotes[$ferramenta]}

      # Separe as flags em variáveis,
      # Aqui fica evidente o porquê a ordem das flags precisa ser igual
      local instalar=$(echo ${flags} | cut -d';' -f1)
      local  remover=$(echo ${flags} | cut -d';' -f2)
      
      # E por fim, armazene cada opção em uma variável
      instalar_pacote="${ferramenta} ${instalar}"
       remover_pacote="${ferramenta} ${instalar}"

      # Saia do laço for e da função
      return 
    }
  done
  # Se nenhum gestor de pacote suportado existir no sistema, mostre essa mensagem:
  echo "Desculpe mas seus sistema não usa um dos gestores de pacote suportados"
  # Termine a execução do script como erro 127
  exit 127
  # O erro 127 indica que o script não conseguiu encontrar o comando, é um padrão
}

DefineQualGestorDePacotes

${instalar_pacote} leafpad    # Instala o Leafpad
 ${remover_pacote} galculator # Remove o Galculator

echo "Fim da demontração"
2 curtidas

Então, estou desenvolvendo em bash script, em um script de automatização para instalar jogos. Como não entendo python, seria complicado pra mim.

Obrigado pela dica, mas olhei e pra mim pareceu um tanto quanto confuso.

Pelo que entendi, o source code que você propôs ele verifica o gestor de pacotes e já instala o programa, correto? Acho q n fui bem específico no que eu realmente preciso, é que tem alguns jogos que podem estar nos repos de distros diferentes, aí eu gostaria de dar a opção para o usuário poder escolher em q tipo de distro (disponível nas opções) ele quer q seja instalado.

Compreendi agora.

Para mim não vazou. Mas obrigado por me informar.

Vou testar aqui.

Ele é basicamente uma simplificação que permite escalonar, pra fazer o que você quer basta adicionar a flag de busca e ver se o pacote existe, um database assim como você quer cresce em progreção geométrica de tamanho, ao invés disso busque o pacote, no caso do apt a flag é “search”:

# Adicione a flag
GestoresDePacotes[apt]="install;remove;search"

function DefineQualGestorDePacotes(){
  # Para cada uma das ferramentas
  for ferramenta in "${!GestoresDePacotes[@]}"; do
    # Verifique se ela existe
    type ${ferramenta} &> /dev/null && {
      # Se existir, pegue as opções,
      local flags=${GestoresDePacotes[$ferramenta]}

      # Separe as flags em variáveis,
      # Aqui fica evidente o porquê a ordem das flags precisa ser igual
      local   instalar=$(echo ${flags} | cut -d';' -f1)
      local    remover=$(echo ${flags} | cut -d';' -f2)
      local  pesquisar=$(echo ${flags} | cut -d';' -f3) # Variável da nova flag
      
      # E por fim, armazene cada opção em uma variável
      instalar_pacote="${ferramenta} ${instalar}"
       remover_pacote="${ferramenta} ${remover}"
       pesquisar_pacote="${ferramenta} ${pesquisar}"

      # Saia do laço for e da função
      return 
    }
  done
  # Se nenhum gestor de pacote suportado existir no sistema, mostre essa mensagem:
  echo "Desculpe mas seus sistema não usa um dos gestores de pacote suportados"
  # Termine a execução do script como erro 127
  exit 127
  # O erro 127 indica que o script não conseguiu encontrar o comando, é um padrão
}

DefineQualGestorDePacotes

# Pesquisa por um pacote, se ele existir, retorne 0 se não, retorne 2
function PacoteExiste(){
  local pacote=$(pesquisar_pacote ^"${1}"$ 2> /dev/null)
  echo ${pacote} | grep "${1}" > /dev/null && return 0
  return 1
}

PacoteExiste "leafpad" && instalar_pacote "leafpad"

Adicionando poucas linhas eu implementei a feature, pesquisando distro a distro, quantas linhas e/ou arquivos você teria que mexer?

1 curtida

Vai depender de cada jogo.
Por exemplo, o UFO: Alien Invasion possui pacotes nos repositórios do Debian, Ubuntu e Gentoo. Ficaria tipo assim para o usuário escolher:
Instalação - UFO: Alien Invasion
[1] Instalar no Ubuntu ou derivados
[2] Instalar em Debian ou derivados
[3] Instalar em Gentoo ou derivados
=> Escolha uma das opções:

Nossa, agora saquei que fiz um auê todo e que nem preciso realmente desta função. Só dar a opção para o usuário escolher e já era. Em todo caso, agradeço a todos que me ajudaram e vou procurar usar as recomendações em futuros caso em que for preciso.

1 curtida

Mano, ou você mantém poucos jogos ou em pouco tempo seu script vai ficar impossível de ser mantido, falo por experiência própria

Uma coisa que você ode fazer é colocar cada jogo em um array associativo também:

declare -A Jogos
Jogos['UFO: Alien Invasion']="pacote;pacote-fallback;pacote-fallback3"

Mas aí se eu pedisse pra instalar o UFO: Alien Invasion teria que pescaria o pacote certo para o tipo de distro e ainda informar o gerenciador de pacotes, não?
Tipo, nem todo jogo que vou por no script está em repositórios das distros, além de que só alguns jogos possuem pacotes em vários distros. Aproveitando a oportunidade, eu lembro q a pouco + de um ano atrás, eu ainda encontrava jogos que pra instalar, precisava baixar um script que baixava ele via git e instalava. Só que n encontro + nenhum jogo com este processo de instalação, teria algum pra me indicar? Eu aprendo melhor como funciona olhando um código já feito do que tendo q elaborá-lo do 0.

Que pena, é uma linguagem divertida. :confused:
Bom agora que ficou mais claro o que vc está imaginando, pela diversão :slight_smile: , acho que faria algo mais ou menos assim :

#! /bin/python
import platform
import subprocess
import textwrap
from argparse import ArgumentParser, RawTextHelpFormatter

import errno

GAMES = {
    1: {"name": "League Of Legends"},
    2: {"name": "Fortnite", "need_repo": {"Fedora": "repo url"}},
    3: {"..."}
}

game_str = ''.join([f"\n{k}: {v}" for k, v in GAMES.items()])

s = textwrap.dedent('''
    Este programa automatiza a instalação de jogos. :) \n
    ''')
parser = ArgumentParser(formatter_class=RawTextHelpFormatter,
                        prog="GameAutomator", description=s)

group = parser.add_mutually_exclusive_group(required=True)
s = textwrap.dedent(f'''
    Jogos que deseja instalar. Se nada for informado, tentará instalar todos.
    {textwrap.indent(game_str, ' '*8)}\n
    ''')
group.add_argument('-i', "--install", type=int, default=None, nargs="*",
                    choices=(1, 2, 3), help=s)

s = textwrap.dedent(f'''
    Jogos que deseja remover. Se nada for informado, tentará remover todos.
    {textwrap.indent(game_str, ' '*8)}\n
    ''')
group.add_argument('-r', "--remove", type=int, default=None, nargs="*",
                    choices=(1, 2, 3), help=s)

CMD = [
    {"fedora": {"apt": {"i": "install", "r": "remove"}}},
    {"fedora": {"dnf": {"i": "install", "r": "remove"}}},
    {"fedora": {"pacman": {"i": "-S", "r": "-R"}}}
]

REPOCMD = {
    ...
}

ARGS = parser.parse_args()
print(ARGS)


def try_remove(args, cmd, games):
    pass # blablabla algo similar ao try_install


def try_install(args, cmd, games):
    for g in args.install:
        game = GAMES[g]
        commd, cargs = "", {}
        if "fedora" in platform.platform().lower():
            commd, cargs = CMD["fedora"].items()

        if not "need_repo" in game:
            try:
                subprocess.call([commd, cargs["i"], game["name"]])
            except OSError as e:
                if e.errno == errno.ENOENT:
                    Exception(f"comando não encontrado: {commd}")
                else:
                    raise Exception(f"algo deu errado ao executar {commd}. :/")
        else:
            pass # faz alguma coisa...


if isinstance(ARGS.install, list):
    if not ARGS.install:
        game_list = list(GAMES.values())
    else:
        game_list = []
    print(f"Instalando {game_list}")
    try_install(ARGS, CMD, GAMES)
        
elif isinstance(ARGS.remove, list):
    game_list = GAMES.keys() if not ARGS.remove else ARGS.remove
    print(f"Removendo {game_list}")
    try_remove(ARGS, CMD, GAMES)

Está incompleto, mas pelo que entendi, acho que seria algo meio que automático, para um número limitado de distros e automático, onde você indica os jogos e ele segue o processo de ir atrás de repositório, etc. Teria algo como:

1 curtida

É só pesquisar pelo pacote como no exemplo que eu dei, sem mistério

Precisa ser bash…

3 curtidas