Em outras palavras, você gostaria de ter um controle remoto ~/.bashrc
, mas não é possível, nem mesmo com outro nome. O Bash não suporta a transmissão de comandos iniciais como argumentos de linha de comando ou através de variáveis de ambiente, eles precisam estar em um arquivo. No entanto, o arquivo não precisa estar no sistema de arquivos!
bash --rcfile /dev/fd/3 3< <(echo 'alias foo="echo hello"')
$ foo
hello
Muitos servidores SSH permitem a transmissão de variáveis de ambiente cujo nome está no formato LC_XXX
, porque geralmente são usados para indicar localidades, que precisam ser transmitidas entre hosts e não têm implicação de segurança. Se o seu permite isso, você pode transmitir o conteúdo do seu .bashrc
por meio de uma variável de ambiente e, em seguida, alimentar essa variável de ambiente em um descritor de arquivo.
LC_BASHRC=$(cat ~/.bashrc; exec 3<&-) \
ssh -t remote.example.com \
'exec bash --rcfile /dev/fd/3 3< <(printf %s "$LC_BASHRC")'
- O conteúdo do local
~/.bashrc
é transmitido para o servidor na variável de ambienteLC_BASHRC
. -
exec 3<&-
é anexado, para fechar o descritor de arquivo depois de ler o arquivo. - No lado remoto, o shell de login é substituído (
exec
) por uma nova instância de bash, que é instruída a ler seu arquivo de inicialização no descritor de arquivo 3. -
3< <(…)
redireciona o descritor de arquivo 3 para uma substituição de comando: a saída deprintf
é alimentada para o processo pai por meio de um canal.
Se o seu shell de login no servidor for /bin/sh
em vez de bash ou ksh, você não poderá usar a substituição do processo diretamente nesse shell, você precisará de uma camada extra:
LC_BASHRC=$(cat ~/.bashrc; exec 3<&-) \
ssh -t remote.example.com \
'exec bash -c '\''exec bash --rcfile /dev/fd/3 \
3< <(printf %s "$LC_BASHRC")'\'
Você pode verificar quais variáveis de ambiente o servidor SSH aceita procurando por AcceptEnv directive in its [
configuration ](http://www.openbsd.org/cgi-bin/man.cgi?query=sshd_config&sektion=5) (
/ etc / sshd_config or
/ etc / ssh / sshd_config ').
Em vez de usar a substituição de comandos 3< <(…)
, você pode usar uma string here. Isso cria um arquivo temporário (em $TMPDIR
ou /tmp
) em vez de um canal, portanto, isso só funcionará se você não se importar em criar um arquivo temporário.
LC_BASHRC=$(cat ~/.bashrc; exec 3<&-) \
ssh -t remote.example.com \
'exec bash --rcfile /dev/fd/3 3<<<"$LC_BASHRC"'
Se você não se importar em criar um arquivo temporário, há uma técnica muito mais simples:
- Copie seu
.bashrc
para um arquivo remoto temporário. Você precisa fazer isso apenas uma vez até que o arquivo temporário seja excluído. - Inicie um shell interativo com
--rcfile
apontando para o arquivo temporário.
remote_bashrc=$(ssh remote.example.com 'bashrc=$(mktemp) && cat >>"$bashrc" && echo "$bashrc"' <~/.bashrc)
ssh -t remote.example.com "exec bash --rcfile '$remote_bashrc'"
Se a implementação do SSH não for muito antiga, você poderá use uma conexão mestre para acelerar o lançamento de vários comandos SSH para o mesmo host.
Se você estiver efetuando login com uma chave e tiver controle sobre o arquivo de chave pública, poderá automatizar mais. Em ~/.ssh/authorized_keys
, uma chave pode ter uma diretiva command=…
que permite executar um comando em vez do que foi especificado na linha de comando. Consulte Como posso definir o ambiente variáveis para um processo de rsync remoto? para mais explicações.
command="if [ -n \"$SSH_ORIGINAL_COMMAND\" ]; then
eval \"$SSH_ORIGINAL_COMMAND\";
else exec bash -c 'bash 3<<<\"$LC_BASHRC\"'; fi" ssh-rsa …
ou
command="if [ -n \"$SSH_ORIGINAL_COMMAND\" ]; then
eval \"$SSH_ORIGINAL_COMMAND\";
else exec bash -c 'bash 3<<<\"alias foo=bar; …\"'; fi" ssh-rsa …
(Isso precisa ser tudo em uma linha, eu só coloco quebras de linha para legibilidade.)