Quão estáveis ​​são as "APIs stdin/stdout" do shell Unix?

Quão estáveis ​​são as "APIs stdin/stdout" do shell Unix?

grepping, awking, sedding e piping são rotinas diárias de um usuário de qualquer sistema operacional do tipo Unix, seja na linha de comando ou dentro de um script de shell (chamado coletivamentefiltrosde agora em diante).

Em sua essência, ao trabalhar com programas CLI Unix "padrão" e shell internos (chamados coletivamentecomandosde agora em diante), os filtros precisam de um formato esperado preciso para stdin, stdout e stderr em cada etapa do filtro para funcionar corretamente. Eu chamo esse formato esperado preciso de algum comando de API deste comando a seguir.

Como alguém com experiência em desenvolvimento web, comparo tecnicamente esse tipo de coleta e processamento de dados comRaspagem da web- uma técnica que é muito instável sempre que há a menor alteração na apresentação dos dados.

Minha pergunta agora está relacionada à estabilidade das APIs de comando Unix.

  1. Os comandos em sistemas operacionais do tipo Unix aderem a uma padronização formal com relação à sua entrada e saída?
  2. Houve casos na história em que atualizações de algum comando importante causaram a interrupção da funcionalidade de algum filtro que foi criado usando uma versão mais antiga do referido comando?
  3. Os comandos Unix amadureceram ao longo do tempo e é absolutamente impossível alterá-los de tal forma que algum filtro possa quebrar?
  4. Caso os filtros possam quebrar de tempos em tempos devido à alteração das APIs de comando, como posso, como desenvolvedor, proteger meus filtros contra esse problema?

Responder1

O padrão POSIX 2008 possui uma seção que descreve"Shell e utilitários". Geralmente, se você seguir isso, seus scripts deverão ser bastante preparados para o futuro, exceto possivelmente para descontinuações, mas isso dificilmente acontece da noite para o dia, então você deve ter bastante tempo para atualizar seus scripts.

Em alguns casos onde o formato de saída para um único utilitário varia amplamente entre plataformas e versões, o padrão POSIX pode incluir uma opção normalmente chamada -pou -Pque especifica um formato de saída garantido e previsível. Um exemplo disso é otimeUtilitário, que tem implementações amplamente variadas. Se você precisar de um formato de API/saída estável, você usaria time -p.

Se você precisar usar um utilitário de filtro que não seja coberto pelo padrão POSIX, então você estará praticamente à mercê dos empacotadores de distribuição/desenvolvedores upstream, assim como estará à mercê dos desenvolvedores web remotos ao fazer web scraping.

Responder2

Vou tentar responder com base na minha experiência.

  1. Os comandos realmente não aderem a uma especificação formal, mas aderem a um requisito de consumir e gerar texto orientado a linhas.

  2. Sim claro. Antes dos utilitários GNU se tornarem um padrão de fato, muitos fornecedores tinham resultados peculiares, especialmente com relação ao pse ls. Isso causou muita dor. Hoje, apenas a HP oferece comandos super peculiares. Historicamente, os utilitários Berkeley Software Distribution (BSD) foram uma grande ruptura com o passado. A especificação POSIX foi uma ruptura com o passado, mas agora é amplamente aceita.

  3. Os comandos Unix realmente amadureceram com o tempo. Ainda não é impossível quebrar algum script escrito para uma versão mais antiga. Pense na tendência recente em direção ao UTF-8 como codificação de arquivo de texto. Essa mudança exigiu a mudança de utilitários básicos como o tr. No passado, o texto simples era quase sempre ASCII (ou algo próximo), então as letras maiúsculas formavam um intervalo numérico, assim como as letras minúsculas. Isso não é mais verdade com UTF-8, então tré possível aceitar diferentes opções de linha de comando para especificar coisas como "maiúsculas" ou "alfanumérico".

  4. Uma das melhores maneiras de "fortalecer" seus filtros é não depender de um layout de texto específico. Por exemplo, don't do cut -c10-24, que depende das posições de uma linha. Use cut -f2em vez disso, o que eliminaria o segundo campo separado por tabulações. awkdivide qualquer linha de entrada em $1, $2, $3... que são separados por espaços em branco por padrão. Depender de conceitos de nível superior, como “campos”, em vez de conceitos de nível inferior, como posição de coluna. Além disso, use expressões regulares: sede awkambos podem fazer coisas com expressões regulares que não se importam com alguma variação na entrada. Outro truque é processar a entrada em algo cujo formato seu filtro possa ser exigente. Use tr -cs '[a-zA-z0-9]' '[\n]'para dividir o texto em uma única palavra por linha, sem pontuação. Você simplesmente não se importa com a aparência do texto de entrada nesse caso.

Responder3

Primeiro, respostas muito breves às suas perguntas:

  1. Padronização formal de convenções de entrada/saída:não
  2. Quebra no passado devido à mudança na produção:sim
  3. Absolutamente impossível quebrar filtros futuros:não
  4. Como posso me proteger contra mudanças:seja conservador

Quando você diz "API", está usando um termo que (para o bem ou para o mal) implica muita formalidade em torno das convenções de entrada/saída de filtro. De maneira muito (e quero dizer "muito") de maneira geral, as principais convenções para dados que podem ser facilmente filtrados são

  • cada linha de entrada é um registro completo
  • dentro de cada registro, os campos são separados por um caractere delimitador conhecido

Um exemplo clássico seria o formato /etc/passwd. Porém, essas convenções padrão são provavelmente violadas até certo ponto com mais frequência do que seguidas à risca.

  • Existem muitos filtros (geralmente escritos em awk ou perl) que analisam formatos de entrada multilinhas.
  • Existem muitos padrões de entrada (por exemplo, /var/log/messages) onde não há uma estrutura de campo bem definida, e técnicas mais gerais baseadas em expressões regulares devem ser usadas.

A sua quarta questão, como proteger-se contra variações na estrutura de produção, é realmente a única sobre a qual pode fazer alguma coisa.

  • Como@jw013 disse, veja o que dizem os padrões posix. Claro, posix não especifica todos os comandos que você deseja usar como fontes de entrada.
  • Se você deseja que seus scripts sejam portáveis, tente evitar as idiossincrasias de qualquer versão de algum comando que você tenha instalado. Por exemplo, muitas versões GNU de comandos unix padrão possuem extensões não padrão. Eles podem ser úteis, mas você deve evitá-los se quiser portabilidade máxima.
  • Tente aprender quais subconjuntos de argumentos de comandos e formatos de saída tendem a ser estáveis ​​em todas as plataformas. Infelizmente, isso requer acesso a múltiplas plataformas ao longo do tempo, porque essas diferenças não serão anotadas em lugar nenhum, mesmo informalmente.

No final, você não pode se proteger totalmente dos problemas que o preocupam e não há um único lugar onde procurar uma declaração "definitiva" sobre o que um determinado comando deve fazer. Para muitos scripts shell, especialmente aqueles escritos para uso pessoal ou em pequena escala, isso simplesmente não é um problema

Responder4

Existem apenas padrões IO de fato - espaços em branco e saída separada por nulos.

Quanto à compatibilidade, geralmente voltamos a verificar os números de versão de filtros individuais. Não que eles mudem muito, mas quando você deseja usar um recurso totalmente novo e ainda deseja que o script seja executado em versões mais antigas, é necessário "ifdef" de alguma forma. Praticamente não há mecanismo de relatório de capacidade, exceto para escrever casos de teste manualmente.

informação relacionada