Estou pensando em usar uma chamada para jq
um script de utilitário que estou escrevendo, em vez de analisar o JSON manualmente.
Para tornar o script o mais portátil possível, quero saber quais versões de Unix/Linux/MacOS/WSL/etc suportam este comando sem qualquer instalação de pacote adicional.
Da mesma forma, no passado, descobri que alguns scripts usam chamadas para wget
, que estão faltando em pelo menos um tipo por padrão.
Isso me fez pensar: existe algum tipo de ferramenta que diga às pessoas se é "seguro" usar um comando arbitrário em seus scripts dessa maneira? Idealmente, ele agiria como o site caniuse, mostrando quais sabores principais suportam ou não um comando em seus shells padrão.
===
EDIT: Agradecendo ao usuário Kusalananda por apontar que meus exemplos não são comandos POSIX, mudei o título para evitar rotulá-los incorretamente como tal.
Existem algumas ferramentas ou sites que podem ser usados para descobrir qual versão de um projeto está disponível em diversas distribuições (incluindo sistemas não-Linux); consulte Existe uma ferramenta/site para comparar o status do pacote em diferentes distribuições Linux?
É muito mais difícil afirmar categoricamente quais sistemas possuem um determinado pacote por padrão. Em alguns casos não existe um padrão realmente confiável; por exemplo, a maioria dos sistemas Debian terá
wget
quando configurado inicialmente (porque é “padrão” lá), mas as imagens de contêiner Debian não o incluem por padrão e não há nada que o obriguewget
a ser instalado em um sistema Debian.Também não há necessidade de os usuários usarem o pacote do sistema (se houver) para fornecer um determinado binário. Eles também podem ter uma versão em pacote e uma versão instalada manualmente disponíveis, e olhar apenas para o pacote pode dar uma falsa impressão ( por exemplo , se você precisar de pelo menos uma versão específica e o pacote instalado for mais antigo, mas o usuário tiver um versão apropriada em seu caminho).
Tudo isso significa que você não pode fazer nada melhor do que verificar a existência de um comando e falhar se não conseguir encontrar todos os comandos necessários, com links para instruções explicando como instalá-los.
Quase nenhum comando estará presente por padrão em todas as versões sem instalação de pacote.
Você pode considerar a seção de utilitários obrigatórios do padrão POSIX , mas embora muitos deles estejam presentes em todos os sistemas (grep, basename, cut, grep, cmp...) outros não são comuns ou precisam de pacotes separados (compress, pax, aqueles que lidam com arquivos SCSS...).
Não há culpa em usar programas adicionais e exigir que eles estejam disponíveis.
Um script genérico necessário
jq
poderia começar com:Uma regra que às vezes uso ao escrever scripts gerais (ou seja, não aqueles onde eu já conheço o sistema e posso assumir que certos programas estão instalados) é considerar que aqueles pacotes que são considerados essenciais pelo Debian/Ubuntu estarão lá, e o resto pode não.
Os essenciais são um conjunto de pacotes que "devem estar disponíveis e utilizáveis no sistema em todos os momentos" ( veja o Manual de Políticas Debian sobre Pacotes Essenciais ).
Os pacotes Debian podem usar programas essenciais sem declará-los. Em todos os outros casos, eles teriam que declarar a dependência. Como tal, se o programa estivesse sendo empacotado em um
.deb
, os utilitários não essenciais, comojq
ouwget
que você testa, são os mesmos que teriam que ser declarados no pacote, enquanto você poderia pular aqueles em, por exemplo, coreutils.Esta lista obviamente não é universal, e pode haver diferenças entre várias distros da família Debian (bem como versões mais recentes, incluindo programas que não eram essenciais em versões anteriores), mas acho que é boa o suficiente. Se estiver em um pacote essencial e em POSIX, provavelmente é seguro usá-lo diretamente. Se não for um pacote essencial, você sabe que pelo menos não estará disponível lá, então verifique.
Algumas advertências:
Mais irritantes do que programas ausentes são aqueles com comportamento diferente/recursos ausentes que você pode querer usar.
Por exemplo:
BASH_VERSION
se precisar verificar a versão do bash que está executando o seu script)sed
comando tem semântica ligeiramente diferente em seu-i
parâmetro no Mac OS (que usa sed do FreeBSD) e na maioria dos Linux (usando GNU sed)wget
você encontra é na verdade um miniaplicativo busybox (que não possui muitos recursos do wget GNU "normal")Ter dependências não é ruim (provavelmente é até a escolha certa) e você não precisa oferecer suporte a todos os sistemas . Especialmente quando você não tem um sistema de teste para testá-lo. Você precisará traçar uma linha em algum lugar, muitas vezes haverá uma ou algumas configurações que você suporta, que são aquelas que você usa e pode testar, e um melhor esforço e uma expectativa geral para apoiar outras.
Não existe tal recurso atualmente. Eu realmente gostaria que houvesse, porque tornaria meu trabalho muito mais simples. A disponibilidade do pacote é resolvida (consulte https://repology.org/ para obter o melhor recurso atualmente para isso), mas não o que é instalado por padrão. Para muitas distribuições Linux isso não é excepcionalmente difícil de verificar mesmo sem instalar, apenas dá trabalho perseguir a árvore de dependências completa (por exemplo, para Arch Linux, veja as dependências do pacote base , embora você precise seguir as dependências para cada coisa depende). O que fica complicado é que a 'base' para uma determinada distribuição geralmente varia de acordo com o destino da instalação (muitas distros deixam uma série de coisas de fora nas imagens do Docker, por exemplo) e possivelmente a escolha do ambiente do usuário (obviamente você obtém um diferente conjunto de dependências folha se você optar por instalar uma GUI).
Falando como alguém que escreve muitos scripts de shell para o trabalho, há algumas coisas que você pode fazer para ajudar a mitigar esses tipos de problemas:
command -v
para procurar comandos. Isso funciona praticamente em todos os lugares em que você se preocupa em oferecer suporte, pode ser trivialmente transformado em umaif
condição (por exemplo:command -v jq >/dev/null 2>&1
) ou usado para atribuir uma variável (por exemplo: `JQ_PATH="$(command -v jq 2>/ dev/null || true)") e evita a possibilidade de tentar invocar aliases definidos pelo usuário (o que quase nunca é o que você deseja fazer em um script portátil).jq
também pode ser feito comjson
o módulo do Python e oprint()
. A interação HTTP/HTTPS básica pode ser feita facilmente com o Pythonurllib
.readlink
pode ser emulado de maneira bastante trivial usando Python. E há muitos outros. A única ressalva é garantir que você lide com as diferenças de versão no próprio Python de maneira sensata, mas dependendo das plataformas de destino e do que exatamente você precisa fazer, isso pode não ser um problema. Observe que esta não é uma sugestão para escrever seus scripts em Python, mas para permitir apython -c
execução de pequenos trechos de código em vez de chamar programas equivalentes.uname
geralmente seja bom o suficiente).