Esta é uma pergunta que eu ia postar aqui há algumas semanas. Como o terdon , entendi que o a .bashrcé fornecido apenas para shells Bash interativos, portanto não há necessidade de .bashrcverificar se ele está sendo executado em um shell interativo. Confusamente, todas as distribuições que eu uso (Ubuntu, RHEL e Cygwin) tiveram algum tipo de verificação (teste $-ou $PS1) para garantir que o shell atual seja interativo. Eu não gosto de programação de cultos de carga, então comecei a entender o propósito deste código no meu .bashrc.
Bash tem um caso especial para reservatórios remotos
Depois de pesquisar o problema, descobri que os shells remotos são tratados de maneira diferente. Enquanto shells Bash não interativos normalmente não executam ~/.bashrccomandos na inicialização, um caso especial é feito quando o shell é chamado pelo daemon de shell remoto :
O Bash tenta determinar quando está sendo executado com sua entrada padrão conectada a uma conexão de rede, como quando executada pelo daemon de shell remoto, geralmente rshdou pelo daemon de shell seguro sshd. Se o Bash determinar que está sendo executado dessa maneira, ele lê e executa comandos de ~ / .bashrc, se esse arquivo existe e é legível. Isso não será feito se chamado como sh. A --norcopção pode ser usada para inibir esse comportamento e a --rcfileopção pode forçar a leitura de outro arquivo, mas rshdnem sshdgeralmente invoca o shell com essas opções ou permite que sejam especificadas.
Exemplo
Insira o seguinte no início de um controle remoto .bashrc. (Se .bashrcfor originado por .profileou .bash_profile, desative-o temporariamente durante o teste):
echo bashrc
fun()
{
echo functions work
}
Execute os seguintes comandos localmente:
$ ssh remote_host 'echo $- $0'
bashrc
hBc bash
- No
iin $-indica que o shell não é interativo .
- Não levando
-em $0indica que a casca não é um shell de login .
As funções de shell definidas no controle remoto .bashrctambém podem ser executadas:
$ ssh remote_host fun
bashrc
functions work
Percebi que o só~/.bashrc é originado quando um comando é especificado como argumento para . Isso faz sentido: quando é usado para iniciar um shell de logon regular ou é executado (e só é originado se explicitamente feito por um desses arquivos).sshssh.profile.bash_profile.bashrc
O principal benefício que posso ver de ter .bashrcoriginado ao executar um comando remoto (não interativo) é que as funções do shell podem ser executadas. No entanto, a maioria dos comandos de um típico .bashrcé relevante apenas em um shell interativo, por exemplo, os aliases não são expandidos, a menos que o shell seja interativo.
Transferências remotas de arquivos podem falhar
Isso geralmente não é um problema quando rshou sshé usado para iniciar um shell de logon interativo ou quando shells não interativos são usados para executar comandos. No entanto, pode ser um problema para programas como rcp, scpe sftpque usam shells remotos para transferir dados.
Acontece que o shell padrão do usuário remoto (como o Bash) é implicitamente iniciado ao usar o scpcomando. Não há menção a isso na página de manual - apenas uma menção scpusada sshpara sua transferência de dados. Isso tem a conseqüência de que, se .bashrccontiver algum comando impresso na saída padrão, a transferência de arquivos falhará , por exemplo,
scp falhará sem erros .
Veja também este relatório de bug relacionado ao Red Hat de 15 anos atrás, o scp quebra quando existe um comando echo no / etc / bashrc (que acabou sendo fechado como WONTFIX).
Por que scpe sftpfalhar
O SCP (cópia segura) e o SFTP (Protocolo seguro de transferência de arquivos) têm seus próprios protocolos para as extremidades local e remota para trocar informações sobre os arquivos que estão sendo transferidos. Qualquer texto inesperado da extremidade remota é (incorretamente) interpretado como parte do protocolo e a transferência falha. De acordo com uma FAQ do Snail Book
O que muitas vezes acontece, porém, é que há declarações em qualquer sistema ou arquivos de inicialização do shell por usuário no servidor ( .bashrc, .profile,
/etc/csh.cshrc, .login, etc.) que mensagens de texto de saída no login, destinados a serem lidos por seres humanos (como fortune, echo "Hi there!", etc.)
Esse código deve produzir apenas saída em logons interativos, quando houver uma
ttyanexada à entrada padrão. Se ele não fizer esse teste, ele inserirá essas mensagens de texto onde elas não pertencem: nesse caso, poluindo o fluxo do protocolo entre scp2/ sftpe sftp-server.
A razão pela qual os arquivos de inicialização do shell são relevantes, é que sshd
emprega o shell do usuário ao iniciar qualquer programa em nome do usuário
(usando, por exemplo, / bin / sh -c "command"). Esta é uma tradição do Unix e tem vantagens:
- A configuração usual do usuário (alias de comando, variáveis de ambiente, umask etc.) entra em vigor quando comandos remotos são executados.
- A prática comum de definir o shell de uma conta como / bin / false para desativá-lo impedirá o proprietário de executar qualquer comando, caso a autenticação ainda tenha êxito acidental por algum motivo.
Detalhes do protocolo SCP
Para aqueles interessados nos detalhes de como o SCP funciona, encontrei informações interessantes em Como o protocolo SCP funciona, que inclui detalhes sobre Executando o scp com perfis de shell falante no lado remoto? :
Por exemplo, isso pode acontecer se você adicionar isso ao seu perfil de shell no sistema remoto:
eco ""
Por que simplesmente trava? Isso vem da maneira como scpno modo de origem aguarda a confirmação da primeira mensagem de protocolo. Se não for 0 binário, espera que seja uma notificação de um problema remoto e aguarde que mais caracteres formem uma mensagem de erro até que a nova linha chegue. Como você não imprimiu outra nova linha após a primeira, seu local scppermanece em um loop, bloqueado read(2). Enquanto isso, depois que o perfil do shell foi processado no lado remoto, scpfoi iniciado o modo coletor, que também é bloqueado read(2), aguardando um zero binário que indica o início da transferência de dados.
Conclusão / TLDR
A maioria das instruções típicas .bashrcé útil apenas para um shell interativo - não ao executar comandos remotos com rshou ssh. Na maioria dessas situações, a definição de variáveis de shell, aliases e funções de definição não é desejada - e imprimir qualquer texto para padronizar é ativamente prejudicial ao transferir arquivos usando programas como scpou sftp. Sair depois de verificar se o shell atual é não interativo é o comportamento mais seguro para .bashrc.