maneira compatível com checkbashisms para determinar o shell atual

17

No meu .profile , eu uso o seguinte código para garantir que aliases e funções relacionadas ao Bash sejam originados somente se o shell de login realmente for Bash :

# If the current (login) shell is Bash, then
if [ "${BASH_VERSION:-}" ]; then
  # source ~/.bashrc if it exists.
  if [ -f "$HOME/.bashrc" ]; then
    . "$HOME/.bashrc"
  fi
fi

Atualmente, estou no processo de colocar meus arquivos de configuração, scripts e funções do shell sob controle de versão. Também iniciei recentemente o processo de remoção de Bashisms casuais de scripts de shell que não se beneficiam de recursos específicos do Bash, por exemplo, substituindo function funcname() por funcname() .

Para meu repositório de arquivos shell, eu configurei um gancho pre-commit que executa o utilitário checkbashisms do Debian pacote devscripts em cada arquivo sh no repositório para garantir que eu não introduza inadvertidamente a sintaxe específica do Bash. No entanto, isso gera um erro para meu .profile :

possible bashism in .profile line 51 ($BASH_SOMETHING):
if [ "${BASH_VERSION:-}" ]; then

Eu queria saber se havia uma maneira de verificar qual shell está sendo executado que não acionaria um aviso em checkbashisms .

Eu verifiquei a lista de variáveis relacionadas ao shell listadas por POSIX na esperança que um deles poderia usado para mostrar o shell atual. Também observei as variáveis definidas em um shell interativo do Dash, mas, novamente, não consegui encontrar um candidato adequado.

No momento, excluímos .profile de ser processado por checkbashisms ; é um arquivo pequeno, por isso não é difícil verificá-lo manualmente. No entanto, tendo pesquisado o problema, ainda gostaria de saber se existe um método compatível com POSIX para determinar qual shell está sendo executado (ou pelo menos uma maneira que não faça com que checkbashisms falhe).

Mais informações / esclarecimentos

Uma das razões pelas quais estou colocando meus arquivos de configuração do shell sob controle de versão é configurar meu ambiente em todos os sistemas nos quais eu efetuo login regularmente: Cygwin, Ubuntu e CentOS (ambos 5 e 7, usando Active Diretório para autenticação do usuário). Na maioria das vezes, faço logon via X ambientes Windows / desktop e SSH para hosts remotos. No entanto, gostaria que isso fosse uma prova do futuro e tivesse menos confiança nas dependências do sistema e em outras ferramentas possíveis.

Eu tenho usado o checkbashisms como uma verificação de sanidade simples e automatizada para a sintaxe dos meus arquivos relacionados ao shell. Não é uma ferramenta perfeita, por exemplo, eu já apliquei uma correção a ela para que ela não reclame sobre o uso de command -v em meus scripts. Enquanto pesquisava, aprendi que o objetivo real do programa é garantir a conformidade com a política do Debian, que, no meu entender, baseia-se no POSIX 2004 em vez de 2008 (ou na revisão de 2013).

    
por Anthony Geoghegan 02.03.2016 / 15:35

4 respostas

15

Seu

# If the current (login) shell is Bash, then
if [ "${BASH_VERSION:-}" ]; then
  # source ~/.bashrc if it exists.
  if [ -f "$HOME/.bashrc" ]; then
    . "$HOME/.bashrc"
  fi
fi
O código

é completamente compatível com POSIX e a melhor maneira de verificar se você está executando bash . É claro que a variável $BASH_VERSION é bash-specific, mas é exatamente por isso que você a está usando! Para verificar se você está executando bash !

Observe que $BASH_VERSION será definido se bash for chamado como bash ou sh . Depois de declarar que você está executando bash , você pode usar [ -o posix ] como um indicador de que o shell foi chamado como sh (embora essa opção também seja definida quando POSIXLY_CORRECT está no ambiente ou bash é chamado com -o posix , ou com SHELLOPTS = posix no ambiente. Mas em todos esses casos, bash se comportará como se chamado como sh ).

Outra variável que você poderia usar em vez de $BASH_VERSION e que checkbashism não parece reclamar, a menos que a opção -x seja $BASH . Isso também é específico para bash , então você também deve poder usar para determinar se está executando bash ou não.

Eu também diria que não é realmente um uso adequado de checkbashisms . checkbashisms é uma ferramenta para ajudar você a escrever scripts portáveis de sh (de acordo com a especificação sh na política Debian, um superconjunto de POSIX), ajuda a identificar sintaxe não padrão introduzida por pessoas escrevendo scripts em sistemas onde sh é um link simbólico para bash .

Um .profile é interpretado por diferentes shells, muitos dos quais não são compatíveis com POSIX. Geralmente, você não usa sh como seu shell de login, mas shells como zsh , fish ou bash com recursos interativos mais avançados.

bash e zsh , quando não chamado como sh e quando o respectivo arquivo de sessão de perfil ( .bash_profile , .zprofile ) não estiver em conformidade com POSIX (especialmente zsh ), mas ainda ler .profile .

Portanto, não é a sintaxe POSIX que você deseja para .profile , mas uma sintaxe compatível com POSIX (para sh ), bash e zsh se você usar esses shells (possivelmente até Bourne como o shell Bourne também lê .profile , mas não é comumente encontrado em sistemas baseados em Linux).

checkbashisms definitivamente ajudará você a descobrir bashisms , mas pode não apontar a sintaxe POSIX que não é compatível com zsh ou bash .

Aqui, se você quiser usar o código bash -specific (como a solução desse erro bash no qual ele não lê ~/.bashrc em shells de login interativo), uma abordagem melhor seria ter ~/.bash_profile faça isso (antes ou depois de obter ~/.profile onde você colocou suas inicializações de sessão comuns).

    
por 02.03.2016 / 22:45
17

Geralmente, um usa $0 para essa finalidade. No site que você vinculou, está:

0
   (Zero.) Expands to the name of the shell or shell script.
    
por 02.03.2016 / 15:46
5

Normalmente, a variável de ambiente SHELL informa o shell padrão. Você não deve precisar fornecer manualmente o arquivo .bashrc (não é verdade, veja a atualização abaixo), o bash deve fazer isso automaticamente apenas para ter certeza de que está no diretório $ HOME.

A outra opção é fazer algo como:

 ps -o cmd= $$

que lhe dirá o comando (sem argumentos, o = sem um valor não exibirá os cabeçalhos das colunas) do processo atual. Exemplo de saída:

 $ps -o cmd= $$
 bash
 $sh
 $ps -o cmd= $$
 sh

ATUALIZAÇÃO:

Eu estou corrigido! :)

O .bashrc nem sempre é originado como mencionado nos comentários abaixo e link

Então você poderia mover seu .bashrc para .bash_profile e ver se isso funciona sem ter que fazer o teste. Se não você tem o teste acima.

    
por 02.03.2016 / 15:43
3

A pergunta é feita para o shell login do usuário, bem como para o shell atual , de maneira que agrade checkbashisms . Se esse for o shell no qual o usuário fez login, eu usaria o de /etc/passwd , por exemplo,

MY_UID=$(id -u)
MYSHELL=$(awk -F: '$3 == '$MY_UID'{ print $7; }' </etc/passwd )

Os usuários podem, obviamente, iniciar um novo shell após o login. É claro que, se um for bash e o outro não, os testes das variáveis de ambiente do bash podem não ajudar.

Alguns podem querer usar getent em vez de apenas o arquivo passwd (mas isso não estaria no escopo da questão).

Com base no comentário sobre o LDAP e na sugestão para logname , essa alternativa formulário pode ser usado:

MY_NAME=$(logname)
MYSHELL=$(getent passwd | awk -F: '$1 ~ /^'$MY_NAME'$/ {print $7;}' )

Ao testá-lo, notei que logname não gosta de sua entrada redirecionada (então deixei a expressão dividida). Uma verificação rápida mostra que getent deve funcionar nas plataformas mencionadas (embora isso devesse ter sido fornecido na pergunta original):

por 02.03.2016 / 23:18