Recursos para programação portátil de shell

65

Quais recursos existem para a programação de shell portátil? A resposta final é testar em todas as plataformas segmentadas, mas isso raramente é prático.

A especificação POSIX / Single UNIX é um começo, mas não informa qual é o nível de suporte de cada implementação nem quais extensões comuns existem. Você pode ler a documentação de cada implementação, mas isso consome muito tempo e não é totalmente preciso.

Parece-me que um formato ideal seria algum tipo de versão anotada pela comunidade da especificação POSIX, em que cada recurso é anotado pelo seu nível de suporte entre as diferentes implementações. Existe uma coisa dessas? Ou existem outros recursos úteis?

Por exemplo, há as páginas de portabilidade de shell de Sven Mascheck , mas trata apenas de elementos sintáticos e de alguns embutidos, e cobre apenas conchas antigas. Estou procurando um recurso mais abrangente.

Gilles 'SO- parar de ser mau'
fonte
2
Nota: não responda aqui apenas para citar um documento de conformidade de uma implementação específica. Se você tiver um desses, a tag wiki correspondente seria um bom lugar.
Gilles 'SO- stop be evil' (
11
Alguém precisa minerar o histórico de revisão de autoconfe Metaconfig(Perl, rn) e recolher todos os truques e seus comentários explicativos em um só lugar.
Geekosaur 23/03
@geekosaur: Boa sugestão. Eu nunca olhei para o interior do autoconf, há algo que alguém possa usar como guia ao escrever seus próprios scripts? Nesse caso, essa seria uma boa resposta para minha pergunta, mesmo que não seja definitiva.
Gilles 'SO- stop be evil' (
5
Tenho certeza de que você pode encontrá-lo facilmente, mas, para o benefício de outras pessoas que seguem este tópico, aqui está um link para uma página relevante do manual do autoconf: gnu.org/software/hello/manual/autoconf/Portable- Shell.html
J. Taylor

Respostas:

32

O manual do autoconf possui uma seção sobre programação de shell portátil .

Embora isso não tenha como alvo específico o POSIX, é provavelmente a coleção mais completa do que fazer e não fazer ao tentar escrever o código do shell portátil.

Riccardo Murri
fonte
3
Esse é um dos melhores recursos e foi criado enquanto escrevia um código no M4 que precisava produzir um código de shell que fosse portátil através do maior número possível de shells.
Tim Post
6

Além de dashe posh, há bournesh(ou bsh), o Heirloom Bourne Shell , que pode ser usado para detectar Bashisms .

O Projeto Heirloom também inclui "The Heirloom Toolchest", uma coleção de mais de 100 utilitários padrão do Unix (que podem servir como ponto de partida para comparar opções de linha de comando).

ralf
fonte
2
Observe que o shell Bourne não é um shell POSIX, tornando seu script portátil para o shell Bourne significaria fazer o downgrade da sintaxe do seu script da linguagem sh padrão do POSIX para o denominador comum entre isso e a sintaxe do shell Bourne. Não vale a opinião, a menos que você queira ser portátil para sistemas antigos (ou Solaris 10 e versões anteriores e não tenha a opção de usar o sh padrão que estava em / usr / xpg4 / bin).
Stéphane Chazelas
5

Semelhante a esta resposta , tente executar seu script em fino .

Além disso, não se esqueça de definir a POSIXLY_CORRECTvariável de ambiente como true, pois isso faz com que muitos programas (não apenas o shell) sigam mais estritamente os padrões POSIX.

Philomath
fonte
4

Escrever seus scripts usando o dash pode ser um começo.

Glenn Jackman
fonte
3
Testar com o dash é o mínimo necessário para evitar dependência acidental dos recursos do ksh / bash, mas estou buscando mais do que isso: conhecendo deficiências em outros shells (por exemplo, o mau manuseio de armadilhas do zsh) e, principalmente, em utilitários de shell (por exemplo, o OpenBSD findainda não implementado -exec +).
Gilles 'SO- stop be evil'
FWIW, o OpenBSD's findfaz -exec utility {} +hoje em dia.
Kusalananda
2

Para um pouco, você pode tentar checkbashismsno devscriptspacote Debian / Ubuntu .

Não é perfeito, mas tem o benefício de ser um ponto de partida existente. Por exemplo, ele não vê as falhas clássicas com sed/ findrelativas ao GNU vs BSD / outras diferenças.

Por padrão, ele é orientado pelo Debian + dash, a -pbandeira pode ser útil no seu caso.

shellholic
fonte
2

Hoje, geralmente você pode encontrar um shell POSIX em um sistema, e isso geralmente significa que você pode criar scripts na linguagem POSIX (módulo executando erros de conformidade).

O único problema é que /bin/shàs vezes não é um shell POSIX. E você deve codificar a #!linha em scripts que devem se comportar como bons executáveis; você não pode simplesmente pedir ao usuário para pesquisar o problema e depois chamar seu script como /path/to/posix/shell myscript.

Portanto, o truque é usar os recursos POSIX em seu script, mas faça com que o script encontre automaticamente o shell POSIX. Uma maneira de fazer isso é assim:

#!/bin/sh

# At this point, we may be running under some old shell
# we have to tread carefully.

# note how we use test rather than [ ] syntax and avoid
# depending on test with no argument producing a failure;
# i.e. "test $posix_shell".

if ! test x$posix_shell = x ; then
  # the three possible shell paths are just an example;
  # please extend as necessary.

  for shell in /usr/xpg4/bin/sh /bin/bash /usr/bin/bash ; do
    if test -x $shell ; then
       posix_shell=$shell
    fi
  done
  if test x$posix_shell = x ; then
    echo "no POSIX shell found"
    exit 1
    # or we could avoid bailing here and just fall back on /bin/sh:
    # echo "falling back on /bin/sh: cross your fingers that it works"
    # posix_shell=/bin/sh
  fi
  export posix_shell

  # plain "$@" is broken in ancient shells! 
  # I seem to recall ${@+"$@"}: not sure if that's the right trick.

  exec $posix_shell $0 ${@+"$@"}  # can we count on exec in legacy shells? 
fi

# phew, at this point in the script we have been re-executed and are
# being interpreted by some reasonably modern shell. We can use $(...)
# command substitution, and other features.

Existem outras abordagens, como a geração de código. Inicie seus scripts com um pequeno script que ocupa um corpo de arquivos de script sem um #! linha e adiciona uma.

A pior coisa possível que você pode fazer é começar a escrever scripts inteiros de forma que sejam executados em um shell Bourne a partir de 1981. Isso é necessário apenas se você precisar escrever para um sistema que realmente não possui outro shell .

Kaz
fonte