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 .bashrc
verificar 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 ~/.bashrc
comandos 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 rshd
ou 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 --norc
opção pode ser usada para inibir esse comportamento e a --rcfile
opção pode forçar a leitura de outro arquivo, mas rshd
nem sshd
geralmente 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 .bashrc
for originado por .profile
ou .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
i
in $-
indica que o shell não é interativo .
- Não levando
-
em $0
indica que a casca não é um shell de login .
As funções de shell definidas no controle remoto .bashrc
també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).ssh
ssh
.profile
.bash_profile
.bashrc
O principal benefício que posso ver de ter .bashrc
originado 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 rsh
ou 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
, scp
e sftp
que usam shells remotos para transferir dados.
Acontece que o shell padrão do usuário remoto (como o Bash) é implicitamente iniciado ao usar o scp
comando. Não há menção a isso na página de manual - apenas uma menção scp
usada ssh
para sua transferência de dados. Isso tem a conseqüência de que, se .bashrc
contiver 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 scp
e sftp
falhar
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
tty
anexada à 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
/ sftp
e 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 scp
no 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 scp
permanece em um loop, bloqueado read(2)
. Enquanto isso, depois que o perfil do shell foi processado no lado remoto, scp
foi 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 rsh
ou 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 scp
ou sftp
. Sair depois de verificar se o shell atual é não interativo é o comportamento mais seguro para .bashrc
.