Esta é uma pergunta que eu ia postar aqui há algumas semanas. Como terdon , eu entendi que um .bashrc é originado apenas para shells Bash interativos, portanto não deve haver necessidade de .bashrc verificar se ele está sendo executado em um shell interativo. Confusamente, all as distribuições que eu uso (Ubuntu, RHEL e Cygwin) tinham algum tipo de verificação (testando $- ou $PS1 ) para garantir que o shell atual é interativo. Eu não gosto de programação de cultos de carga então comecei a entender o propósito de este código no meu .bashrc .
Bash tem um caso especial para shells remotas
Depois de pesquisar o problema, descobri que os shells remotos são tratados de forma diferente. Embora os shells Bash não interativos não executem normalmente os comandos ~/.bashrc na inicialização, um caso especial é feito quando o shell é Chamado pelo daemon de shell remoto :
Bash attempts to determine when it is being run with its standard input connected to a network connection, as when executed by the remote shell daemon, usually
rshd, or the secure shell daemonsshd. If Bash determines it is being run in this fashion, it reads and executes commands from ~/.bashrc, if that file exists and is readable. It will not do this if invoked assh. The--norcoption may be used to inhibit this behavior, and the--rcfileoption may be used to force another file to be read, but neitherrshdnorsshdgenerally invoke the shell with those options or allow them to be specified.
Exemplo
Insira o seguinte no início de um controle remoto .bashrc . (Se .bashrc for originado por .profile ou .bash_profile , desative temporariamente isso durante o teste):
echo bashrc
fun()
{
echo functions work
}
Execute os seguintes comandos localmente:
$ ssh remote_host 'echo $- $0'
bashrc
hBc bash
- Não
iin$-indica que o shell é não interativo . - Nenhum líder
-in$0indica que o shell não é um shell de login .
As funções do shell definidas no controle remoto .bashrc também podem ser executadas:
$ ssh remote_host fun
bashrc
functions work
Notei que o ~/.bashrc é somente originado quando um comando é especificado como o argumento para ssh . Isso faz sentido: quando ssh é usado para iniciar um shell de login regular, .profile ou .bash_profile são executados (e .bashrc é apenas originado se explicitamente feito por um desses arquivos).
O principal benefício que vejo ao ter o .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 em um .bashrc típico só é relevante em um shell interativo, por exemplo, os aliases não são expandidos, a menos que o shell seja interativo.
Transferências de arquivos remotas podem falhar
Normalmente, isso não é um problema quando rsh ou ssh são usados para iniciar um shell de login 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 remotas para transferir dados.
Acontece que o shell padrão do usuário remoto (como o Bash) é iniciado implicitamente ao usar o comando scp . Não há menção a isso na página man - apenas uma menção de que scp usa ssh para sua transferência de dados. Isso tem como consequência que se o .bashrc contiver algum comando que imprima na saída padrão, as transferências de arquivos falharão , por exemplo,
scp falha sem erro .
Veja também este relato de bug relacionado à Red Hat de 15 anos atrás, scp quebra quando há um comando echo em / etc / bashrc (que foi encerrado como WONTFIX ).
Por que scp e sftp falham
SCP (cópia segura) e SFTP (Secure File Transfer Protocol) tem seus próprios protocolos para os fins locais e remotos para trocar informações sobre o (s) arquivo (s) sendo transferido (s). Qualquer texto inesperado do terminal remoto é (erroneamente) interpretado como parte do protocolo e a transferência falha. De acordo com uma FAQ do Snail Book
What often happens, though, is that there are statements in either the system or per-user shell startup files on the server (
.bashrc,.profile,/etc/csh.cshrc,.login, etc.) which output text messages on login, intended to be read by humans (likefortune,echo "Hi there!", etc.).Such code should only produce output on interactive logins, when there is a
ttyattached to standard input. If it does not make this test, it will insert these text messages where they don't belong: in this case, polluting the protocol stream betweenscp2/sftpandsftp-server.The reason the shell startup files are relevant at all, is that
sshdemploys the user's shell when starting any programs on the user's behalf (using e.g. /bin/sh -c "command"). This is a Unix tradition, and has advantages:
- The user's usual setup (command aliases, environment variables, umask, etc.) are in effect when remote commands are run.
- The common practice of setting an account's shell to /bin/false to disable it will prevent the owner from running any commands, should authentication still accidentally succeed for some reason.
Detalhes do protocolo SCP
Para os interessados nos detalhes de como o SCP funciona, encontrei informações interessantes em Como funciona o protocolo SCP que inclui detalhes sobre Execução de scp com perfis de shell falantes no lado remoto? :
For example, this can happen if you add this to your shell profile on the remote system:
echo ""
Why it just hangs? That comes from the way how
scpin source mode waits for the confirmation of the first protocol message. If it's not binary 0, it expects that it's a notification of a remote problem and waits for more characters to form an error message until the new line arrives. Since you didn't print another new line after the first one, your localscpjust stays in a loop, blocked onread(2). In the meantime, after the shell profile was processed on the remote side,scpin sink mode was started, which also blocks onread(2), waiting for a binary zero denoting the start of the data transfer.
Conclusão / TLDR
A maioria das instruções em um típico .bashrc é útil apenas para um shell interativo - não ao executar comandos remotos com rsh ou ssh . Na maioria das situações, não é desejado definir variáveis de shell, aliases e funções definidoras - e imprimir qualquer texto como padrão é 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 .