Como meu script pode determinar se está sendo executado por bash ou dash?


13

Estou executando uma nova instalação Oneiric (ou seja, não uma atualização) em dois sistemas diferentes e executando o mesmo conjunto de problemas aparentemente relacionados.

O mais frustrante é que, quando eu uso o .profile e o .bashrc que carrego comigo do Mac OS X, o login no X via LightDM me desconecta imediatamente. Acredito que isso seja causado pelo fato de que, ao executar "/ bin / sh", ele se comporta como / bin / dash, mas ainda tem a variável $ SHELL definida como / bin / bash.

Extrapolação

Eu tenho um enorme .bashrc. Você pode vê-lo aqui, se quiser, mas seu conteúdo provavelmente não é relevante, além do fato de estar cheio de basismos e de funcionar sem erros no xterm ou no console virtual.

Minha .profileaparência é esta (abreviada):

case $SHELL in 
*bash*)
    if [ -f $HOME/.bashrc -a -r $HOME/.bashrc ]; then
        . $HOME/.bashrc
    fi
    ;;
esac

Se eu tentar efetuar login no X via LightDM, ele efetuará o logoff imediatamente. Eu recebo erros .xsession-errorsrelacionados ao meu .bashrc que se parecem com este (abreviado):

/home/mrled/.bashrc: 103: [[: not found
[: 103: Linux: unexpected operator
[: 274: -P :: unexpected operator
/home/mrled/.bashrc: 520: complete: not found

Como eu disse, quando executo o bash em um console virtual, não recebo esses erros. Além disso, se eu remover meu .profile, posso fazer login no X muito bem. (Também posso fazer login em um console virtual e usá-lo startxpara iniciar uma sessão X que funcione, mas essa não é uma solução de longo prazo).

No entanto, eu descobri que se eu correr /bin/sh -l, eu não obter os erros. Aqui está uma sessão de exemplo (nota: o prompt do bash para o qual simplifiquei bash>e o prompt sh é apenas $):

bash> echo $SHELL
/bin/bash
bash> echo $BASH_VERSION
4.2.10(1)-release
bash> /bin/sh -l
/home/mrled/.bashrc: 103: [[: not found
[: 103: Linux: unexpected operator
[: 274: -P :: unexpected operator
/home/mrled/.bashrc: 520: complete: not found
$ echo $SHELL
/bin/bash
$ echo $BASH_VERSION

$

Q1: Por que isso está acontecendo?

Eu entendo que / bin / sh agora aponta para o dash em vez do bash , mas se isso é verdade, por que $SHELLainda está retornando /bin/bash?

P2: O que posso fazer para solucionar isso?

Existe uma maneira de contornar isso? Quero manter meu perfil carregando .bashrc para obter o mesmo ambiente nos shells de logon e não-logon, mas obviamente só quero que ele seja carregado para o bash, não / bin / sh mascarado como bash.

Você deve ter notado a diferença no conteúdo das variáveis ​​$ BASH_VERSION acima. Eu tentei agrupar meu .profile em algo como isto:

if [ -n $BASH_VERSION ]; then
    # the rest of my .profile as above
fi

O -nteste deve retornar true somente se o comprimento da string for diferente de zero, no entanto, embora na sessão acima, quando estou executando, /bin/sh -lele retorne uma string vazia para $ BASH_VERSION, quando incluída no meu .profile como este , passa no teste! Eles procedem da fonte do meu .bashrc e me dão os mesmos erros de antes.

Agora estou realmente confuso.


Observe que dash -ltambém mostra $SHELLter o valor /bin/bash.
Scott Severance

3
$SHELLé o que o último campo em /etc/passwd(ou getent passwd) diz.
Pausado até novo aviso.

@DennisWilliamson Obrigado , é o que eu precisava saber para encontrar a resposta certa.
Micah R Ledbetter

Você está fazendo isso errado. Você deve colocar um ambiente não específico do ~/.profilebash, itens específicos do bash ~/.bashrce ter a ~/.bash_profileorigem dos dois.
nyuszika7h

Respostas:


12

Você pode fazer o fato de que $BASH_VERSIONestá em branco no dashtrabalho para você:

if [ "$BASH_VERSION" = '' ]; then
    echo "This is dash."
else
    echo "This is bash."
fi

2
A técnica "x" é arcaica e só é necessária em conchas antigas . Usoif [ "$BASH_VERSION" = '' ]
pausado até novo aviso.

@DennisWilliamson: Obrigado. Eu pensei que sua técnica era específica para o Bash, mas eu apenas a coloquei no Dash e funcionou. Eu editei minha resposta.
Scott Severance

Ou apenas use-n , ou nada . (. 1, embora = ''funciona perfeitamente bem.)
Elias Kagan

5

Você só precisa usar aspas na variável BASH_VERSIONpara usar-n

if [ -n "$BASH_VERSION" ];then
 echo "this is bash"; 
else 
 echo "this is dash";
fi

1
como [ "$EMPTY_STRING" ]avalia false, você nem precisa do -n. Você só precisa citar a variável
jeberle

2

Use /proc/[PID]/cmdlinepara ver com o que o script está sendo executado e teste o que ele contém. A $$variável nos fornecerá o PID do shell em execução. Assim, podemos criar um script como este,

#!/bin/bash
if grep -q 'bash' /proc/$$/cmdline ;
then
    echo "This is bash"
else
    echo "This is some other shell"
fi

Aqui está um teste do mesmo script:

$> bash test_script.sh                                                                                                
This is bash
$> dash test_script.sh                                                                                                
This is some other shell

Isso não funcionará no Mac. Marque $ BASH_VERSION.
precisa

2
@AustinBurk, ele não precisa funcionar no Mac. Este é o Ask Ubuntu.
TheWanderer

@ Zacharee1 oh danado, eu não estava prestando atenção:,)
Austin Burk

Não quero editar isso longe do que você pretende, mas sugiro mencionar as limitações desse método. Bash não precisa ter bashem seu nome; não é incomum que o bashexecutável seja executado através de um link simbólico com outro nome. Normalmente, alguém ainda gostaria de considerar esse Bash. Além disso, o padrão é correspondido em qualquer lugar/proc/$$/cmdline , o que deve ser possível de corrigir, mas lembre-se de que os argumentos cmdlinesão delimitados por caracteres nulos. grep -qE '(^|/)bash$'parece que deve funcionar, mas dá um falso positivo quando qualquer argumento é bash.
Eliah Kagan 31/08/19

@EliahKagan Sinta-se à vontade para editar minhas respostas a qualquer momento - você possui experiência suficiente para saber que suas edições podem oferecer apenas melhorias. A resposta foi escrita quando eu era muito mais verde com conchas do que sou agora.
Sergiy Kolodyazhnyy
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.