'switch' baseado no shell

7

Eu gostaria de source (isto é, não chamar ) um script de qualquer shell (bash / csh são os principais alvos, mas fish, zsh, ksh e rc também seria interessante).

Eu gostaria que o script fosse um único arquivo, ou seja, não um arquivo para cada dialeto de shell.

Posso fazer isso?

Estou pensando em algo parecido com:

  if shell is bash then
    # bash code here
  else
    if shell is csh then
      # csh code here
    else
      if shell is xxxsh then
        # xxxsh code here
      fi
    endif
  fi

Então eu posso fazer:

csh% source my_script
bash$ . my_script

O problema é - é claro que if não é o mesmo em cada dialeto, então eu de alguma forma preciso usar a sintaxe que é válida para cada shell.

Editar

Detectar o shell é o primeiro passo do determinar o shell no script durante o tempo de execução está fazendo um ótimo trabalho.

Um passo igualmente importante é como o código para as diferentes seções de shells deve ser citado para não confundir outros shells. Pense: Como você pode na seção do bash ter um <<here_document contendo todos os caracteres em todas as combinações legais no bash, mas ilegal em qualquer outro shell sem que isso confunda os outros shells. Isso não é coberto por nenhuma das respostas / respostas vinculadas.

    
por Ole Tange 22.10.2015 / 00:37

3 respostas

2

Em vez de escrever fragmentos de código para cada shell, você deve apenas escrever um código portátil, que pode ser interpretado pela maioria dos shells. Você deve examinar o Idioma de Comando do POSIX Shell . Este é um padrão como um shell (que homenageia o POSIX) deve interpretar o código.

Muitos shells, como bash , podem ser configurados para se comportarem como um shell POSIX. Cada shell tem seus recursos ganhos e notações específicas. Aviod eles completamente em scripts portáteis.

    
por 22.10.2015 / 00:59
2

Para csh-like versus Bourne-like, você poderia fazer:

start=:#||:<<"goto end="

echo "(t)csh code here"
if { bindkey >& /dev/null } then
  echo tcsh
endif

goto end=

echo Bourne-like code here
if [ -n "$BASH_VERSION" ]; then
  echo bash
fi

end=:

Explicado:

  • start=: seria tratado como uma declaração de rótulo em csh e atribuição de variável em sh , portanto, duas operações inofensivas.
  • Em start=:# , esse # é tratado como um líder de comentários csh , mas não em sh , pois não é um token separado. Então, o que depois disso é comentado por csh , mas não por sh .
  • uma atribuição de variável é sh tem um status de saída bem-sucedida (desde que as atribuições não envolvam substituições de comandos), portanto o comando à direita do operador || não será executado.
  • Esse comando :<<"goto end="...goto end não é executado mas é analisado e ignorado (o fato de que "goto end" é citado evita várias expansões dentro do documento aqui). Uma observação, no entanto: no shell Bourne (e somente no shell Bourne), um arquivo temporário ainda é criado.
  • Portanto, toda a seção até goto end= é ignorada pelo shell do tipo Bourne e executada por csh . goto end= faz com que csh ignore a parte entre isso e end=: (uma atribuição de variável inofensiva em shells semelhantes a Bourne).

Quanto mais suporte de shell você adicionar, mais complicado ele fica. Para fish , especialmente, é bastante complicado, pois verifica a sintaxe de todo o evento de script nas partes que ele não executa.

Veja também:

por 05.11.2015 / 17:03
-1

Eu assumo que a razão pela qual você quer fazer isso é por portabilidade. As respostas acima dão uma pista. Se você assumir que o shell Bourne (sh) é o mínimo denominador comum e disponível em qualquer lugar (Linux, Solaris, Unix, AIX, etc.), então você pode colocar um #!/bin/sh no início do seu script e escrever todo o seu script usando apenas os recursos do sh. (Eu acho que no Linux, sh é apenas um alias para o bash, porque o bash é um superconjunto do shell Bourne, mas não importa, ele ainda deve funcionar.)

Um pequeno refinamento é assumir que sh está sempre lá, mas você pode precisar do poder extra e da conveniência de alguns dos shells mais avançados. então você poderia escrever uma versão do script para cada um dos shells que você suporta, por exemplo script.bash, script.zsh, script.ksh, script.csh etc. cada um começando com sua própria linha shebang e, em seguida, no arquivo script.sh, você diria algo como:

#!/bin/sh
if [[ -e /bin/ksh ]] ; then 
 ./script.ksh
 exit
elif [[ -e /bin/csh ]] ; then
 ./script.csh
 exit
fi

etc.

Outra sugestão é estudar o código-fonte da cadeia de ferramentas de ferramentas automáticas. Aquelas coisas que correm quando você faz um ./configure; faço ; faça a instalação. O pessoal do GNU tem feito muitas coisas inteligentes para garantir que seus scripts sejam executados em todos os ambientes.

    
por 22.10.2015 / 01:07