Como eu * confio * e * simplesmente * obtenho o nome atual do interpretador de shell?

9

Estou procurando uma maneira simples e confiável de obter o nome do shell atual de dentro de um script ou arquivo ( não da linha de comando). Eu esperava apenas fazer isso, $(basename "$SHELL")mas se meu shell de login for zshe eu tenho o seguinte código em some_script.sh

this_shell=$( basename "$SHELL" )
echo "The Shell is $this_shell"
echo "The Shell is $0"

e eu corro com ele bash some_script.sh, ele ainda lista, em zshvez de bashser o intérprete usado /bin/bash. Não sei por que os designers de shell escolheram mostrar o shell padrão em vez do shell atual, mas parece que é com isso que estamos presos.

Existem outras perguntas um pouco semelhantes ( aqui e aqui ), mas suas respostas são insuficientes de várias maneiras.

  1. Eles geralmente assumem que o usuário está tentando descobrir qual shell interativo está usando atualmente, mas isso é loucura. Eu sei em qual shell estou digitando comandos - preciso de um código que possa ser executado em qualquer lugar para determinar qual shell ele está usando.
  2. Eles geralmente oferecem várias coisas diferentes para tentar - novamente, como se você estivesse na linha de comando e pode apenas mexer até aprender que está usando o bash - mas eu preciso de uma coisa única que seja confiável em todos os contextos.
  3. Eles geralmente dão coisas que são totalmente inúteis nos scripts, como echo $0. Isso falha, como mostrado no script acima. (Sim, ele funciona em uma linha de comando do shell interativo, mas por que você nunca sabe qual shell está usando?)
  4. Às vezes, eles dão comandos que (nos meus testes limitados) incluem as informações corretas, como ps -p $$, mas não possuem comandos sed / awk compatíveis com várias plataformas e vários shell para canalizá-lo para obter apenas o nome do shell e ignorar as outras informações que aparecem para o passeio.
  5. Eles incluem coisas que só funcionam em algumas conchas, como $BASH_VERSIONe $ZSH_VERSION. Quero apoiar como muitas conchas quanto possível, tais como fish, csh, tcsh.

Como detecto de maneira confiável e precisa qualquer shell atual ? Estou procurando por algo que funcione em várias plataformas, em scripts e no maior número possível de shells possíveis e razoáveis 1 .

ATUALIZAÇÃO : Quando postei essa pergunta, esperava que houvesse alguma facilidade embutida nas conchas para nos fornecer essas informações, o que parece não ser o caso. Como agora parece inevitável contar com algo fora dos escudos, devo deixar mais explícito que estou pedindo umasolução de plataforma cruzada (que, embora implícita pelas minhas objeções a outras respostas acima, pode ser fácil perder se você não leia a pergunta com atenção).

Atualização 2 Se alguém ainda acredita que essa é uma duplicata da pergunta somente sobre Linux, porque a resposta de Stéphane não é somente Linux, eis as diferenças entre o que estou pedindo e o que ele forneceu. (Observe que o que ele escreveu é engenhoso, e eu não estou brincando, mas isso não resolve o meu problema.)

  1. Estou procurando por algo simples e confiável , que
  2. pode ser adicionado a qualquer definição de script ou função (que seriam originados por um .zshrcou .bash_profileou qualquer outro) em galho.
  3. Você não pode usar o script dele como um utilitário externo que passa o nome do intérprete para o script / função de chamada, pois ele sempre será interpretado pelo intérprete padrão e retornará isso. Isso torna difícil ou impossível de usar para meus propósitos. Se possível, ainda é muito, muito difícil, e a solução para fazê-lo funcionar não é dada na resposta. Portanto, ele não respondeu à minha pergunta, portanto, não é uma duplicata.

Se você quiser ver algo que vai funcionar, dê uma olhada ShellDetective no GitHub . Isso pode facilitar a visualização das diferenças entre o que já está presente no SE e o que esta pergunta está procurando (e de fato foi escrita para satisfazer as necessidades dessa questão, que não foram atendidas em nenhum outro lugar).


(PS se você não pode acreditar que há um caso de uso para isso, imagine funções que são de origem em .zshrc, .bash_profileou .profiledependendo de qual servidor está sendo usado e que conchas que tem disponível. Eles estão de origem para que eles não têm nenhuma linha shebang. Eles são mais úteis se puderem funcionar em qualquer shell, mas às vezes eles precisam saber em qual shell estão para saber como se comportar.)


1 Não estou preocupado com "conchas" que não sejam conchas no sentido tradicional da palavra. Eu não estou preocupado com alguma concha que um cara escreveu para si mesmo. Estou preocupado apenas com os shells reais que realmente ocorrem na natureza e que alguém pode ter que usar ao fazer login em algum servidor no qual eles não podem simplesmente instalar os shells que quiserem.

iconoclasta
fonte
Para ler a discussão inteiramente fora de tópico sobre se o Python é um shell: veja aqui
iconoclast
2
Citando a resposta de Gilles à pergunta Qual é a diferença exata entre um 'terminal', um 'shell', um 'tty' e um 'console'?   - “Um shell é a interface principal que os usuários veem quando fazem login, cujo objetivo principal é iniciar outros programas.” Na IMO, basta eliminar o Perl e o Python da categoria "shell".
G-Man diz 'Restabelecer Monica
Vagamente relacionado: Script de compatibilidade: Economize $? para uso posterior . Uma abordagem sugerida: faça uma conclusão das diferenças nas sintaxes dos diferentes shells dizendo sh -c "…"e faça a maior parte do trabalho na sintaxe do shell POSIX.
G-Man diz 'Restabelecer Monica
2
Por que você quer isso ? Alguns shells, utilizáveis ​​como shells de logon, têm sintaxe muito incompatível (alguns shells são linguagens do tipo Lisp!), Então não entendo por que você deseja fazer isso. Se você estiver codificando arquivos fonte, precisará codificar várias variantes e solicitar ao usuário que escolha a apropriada.
Basile Starynkevitch
1
Minha segunda pergunta é um exemplo de disfarçar uma concha. O que você faz se um script é executado por um intérprete executável cujo nome não corresponde ao idioma que o intérprete interpreta? Se eu tirar uma cópia do csh, renomeie-a fishe use-a para executar seu script, deseja fishou csh?
Gilles 'SO- stop be evil' em

Respostas:

5

Eu tive ótimos resultados com essa combinação:

ps -p $$ | awk '$1 != "PID" {print $(NF)}'

No Tru64 (OSF / 1), a saída tem parênteses em torno do shell. Prenda tr -d '()'para removê-los.

ps -p $$ | awk '$1 != "PID" {print $(NF)}' | tr -d '()'  

Aparece para trabalhos em todos os shells, no Solaris 10 e RHEL 5.7 / 6.4. Não testou outras distribuições, como Debian, Ubuntu ou Mint, mas acho que todas deveriam funcionar da mesma maneira; Eu também não tenho idéia se o FreeBSD funcionaria.

insira a descrição da imagem aqui

Chris Embry
fonte
3
Não funciona em scripts (retornará o nome do script em vez)
Qw3ry
2

Então, ainda estou tentando explicar isso, mas acho que tenho uma ideia que funcionará. Como você notou, o que você está tentando fazer é, se não impossível, extremamente difícil de fazer em todas as conchas (cada variante adicionada ao poliglota aumenta a complexidade a uma taxa maior que a linear). você provavelmente poderia fazê-lo se se dividir em Bourne (sh, ash, dash, bash, ksh, pdksh, zsh etc.) e conchas no estilo c (csh, tcsh, fish, etc.), mas a variação entre as cshvariantes apresenta vários recursos interessantes desafios.

Então, vamos trapacear e escrever nossa rotina de detecção em uma linguagem conhecida (bash com uma linha shebang, C, perl, python, qualquer que seja) e determinar o nome do executável do pai. podemos então usar dois truques para obter as informações de volta aos pais, ou seja, retornar valor (es) e uma única palavra escrita como padrão. Em sh descendentes, retornaríamos 0 e escreveríamos o nome do shell, pois todos eles têm um bom manuseio de backtick. na família C de shells, podemos começar a incrementar o valor de retorno para cada conjunto de incompatibilidades que precisamos solucionar. Valores de retorno acima de duzentos indicariam erros começando com tudo, mas tudo bem, mas não sei dizer quem é meu pai aos duzentos.

O programa interno parece fácil no linux ( /proc/ppid/exeé metade da batalha). Tenho certeza de que isso pode ser feito no bsd com as opções ps, mas não tenho um sistema bsd em execução no momento para testar, e meu mac precisa de um novo disco rígido (e é apenas 10,4 de qualquer maneira). Embora reduza significativamente os problemas de sintaxe do shell, ele apresenta um conjunto diferente de problemas de compatibilidade. Eu ainda acho que tem possibilidades.

hildred
fonte
Esse é o insight em que eu finalmente decidi - que você precisa de um programa externo para fazer o trabalho - embora eu tenha entendido isso ao ler o comentário de G-Man, sobre o sh -c "..."qual ele tirou outra pergunta . (Desculpe: Eu saltei sua resposta no início porque eu não vi nenhum código nele, e só voltou e lê-lo mais tarde.)
iconoclasta
Existe um paradoxo na pergunta do @ iconoclast. Ele quer chamar isso de um script (observe que alguns shells não suportam funções) que podem ser originados de qualquer shell, de modo que presumivelmente já é poliglota, portanto já deve ter algum suporte para descobrir o que está sendo interpretado. Na minha experiência, escrevendo código poliglota (meu which_intepreter é um exemplo extremo, mas ver também lá por um shell de apenas um é extremamente difícil, e geralmente não vale o esforço.
Stéphane Chazelas
@ StéphaneChazelas: Eu acho que você está certo que geralmente não vale a pena o esforço (certamente geralmente não, e talvez sempre não) mas eu não estou pronto para desistir ... Eu acho que as quebras de problema em 2 problemas realmente: 1º recebendo o nome do shell e o segundo uso. Ambos (pelo menos praticamente) requerem ajuda externa para evitar as limitações das conchas que você poderia estar usando. Resolvi o primeiro problema com um pequeno utilitário escrito em Crystal e, quando encontro tempo, também quero resolver o segundo. Aliás, sua solução é brilhante, mas obviamente muito complexa.
Iconoclast
@iconoclas, supondo que você possa recuperar o nome do shell de maneira confiável (observe que a substituição de comandos e a sintaxe de atribuição de variáveis ​​variam entre os shells), você não pode fazer coisas como case $shell in sh)...(que é sintaxe apenas Bourne) ou switch ($shell)(apenas csh). test "$shell" = "sh" && do-somethingtrabalha em csh/ sh/ rc/ es, mas não fish...
Stéphane Chazelas
Sim, eu já me deparei com isso. O pior é que o peixe nem carrega um script com sintaxe que ele não gosta, então você não pode simplesmente enviar o STDERR para /dev/null. Mas tenho uma solução, que vou postar assim que estiver tudo funcionando.
Iconoclast
1

tente algo assim

shell_bin=$(ps h -p $$ -o args='' | cut -f1 -d' ')
echo $shell_bin
Dany Flores
fonte
Isso falha cshe tcsh.
Iconoclast
com uma pequena modificação que irá trabalhar em fish, mas, em seguida, apenas em fish, infelizmente: ps h -p %self -o args='' | cut -f1 -d' '. Isso cria um problema galinha e do ovo ... você tem que saber que você está em fish, a fim de executar a fishversão do código ...
iconoclasta
@ iconoclast- set shell_bin=`ps -p $$ -o args='' | cut -f1 -d' '`- irá trabalhar com CSH, mas não os outros
darkheart
@DarkHeart: na verdade, que não consegue, uma vez que a atribuição de variável não era o problema em csh/ tcsh, foi esta parte: ps -p $$ -o args='' | cut -f1 -d' ', que retorna -shem csh, e -cshem tcsh.
iconoclast
1

Eu acredito que você nem sempre pode obter o nome do shell atual e acho que você deve estar ciente das limitações do que é possível.

Nas distribuições Linux, a maioria dos usuários teria bash como logon e shell interativo (já que bashé o shell padrão na maioria das distribuições). Alguns usuários que definiu seu shell para zsh, csh(e variantes) ou para fish.

(Como outros comentários e respostas explicar, encontrar confiável a casca fora de bash, zsh, tcsh, fishjá é um desafio)

Mas alguns usuários estranhos pode definir a sua shell de login para algo totalmente diferente - um interpretador Lisp, scsh, es, alguma linguagem de script à la Python, ou Ocaml, ou Perl, etc ...- e é sua liberdade para fazê-lo. Provavelmente, algumas pessoas estão codificando seu próprio shell e usando-o de forma interativa. Mesmo que você tenha encontrado o shell estranho, não poderá fazer nada útil (por isso acredito que você não deve tentar obter o nome do shell).

Então eu acho que você está codificando algum arquivo fonte (talvez gerando um) para configurar algum software. Então, apenas explique o que você está fazendo e codifique o caso comum de bash(e talvez zsh& tcsh) ....

Basile Starynkevitch
fonte
-2

use abaixo por sua conta e risco

tmp=`head -n 1 $0`
SHELL_BIN=`readlink -f ${tmp#*!}`
SHELL=${SHELL_BIN##*/}
gwillie
fonte
ele está me dando uma linha em branco ... mas se eu entendo o que você está tentando fazer é muito inteligente
iconoclasta
Não deve dar-lhe uma linha em branco, a menos que -fopção no readlink, algumas implementações não tem esse interruptor
gwillie
Estou no OS X, e a página de manual é listada -fcomo uma opção disponível, considerando-a formatcomo argumento.
iconoclast
Isso pode funcionar em alguns casos especiais se $ 0 for um script (iniciado por #! / ...), mas essa não é a configuração usual. Aqui, a maioria dos US $ 0 aponta para um arquivo ELF.
readlinknão trabalhando no meu puredarwin vm, então não faço ideia do que está acontecendo lá.
Gwillie