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.
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.
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…
#! /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:
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.
O screenFetch faz isso que você deseja, você poderia dar uma olhada lá e ver o que você pode utilizar.
Saudações.
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
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.
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"
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?
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.
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.
Bom agora que ficou mais claro o que vc está imaginando, pela diversão , 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:
É só pesquisar pelo pacote como no exemplo que eu dei, sem mistério
Precisa ser bash…