Questa è una domanda che avrei pubblicato qui qualche settimana fa. Come terdon , ho capito che a .bashrc
proviene solo per shell Bash interattive, quindi non dovrebbe essere necessario .bashrc
verificare se è in esecuzione in una shell interattiva. Confusamente, tutte le distribuzioni che utilizzo (Ubuntu, RHEL e Cygwin) hanno avuto un qualche tipo di controllo (test $-
o $PS1
) per garantire che la shell corrente fosse interattiva. Non mi piace la programmazione di culto del carico, quindi ho iniziato a capire lo scopo di questo codice nel mio .bashrc
.
Bash ha un caso speciale per shell remote
Dopo aver studiato il problema, ho scoperto che le shell remote sono trattate in modo diverso. Mentre le shell Bash non interattive normalmente non eseguono ~/.bashrc
comandi all'avvio, viene creato un caso speciale quando la shell viene invocata dal daemon di shell remoto :
Bash tenta di determinare quando viene eseguito con il suo input standard collegato a una connessione di rete, come quando viene eseguito dal daemon di shell remoto, in genere rshd
, o dal daemon di shell sicuro sshd
. Se Bash determina che viene eseguito in questo modo, legge ed esegue i comandi da ~ / .bashrc, se quel file esiste ed è leggibile. Non lo farà se invocato come sh
. L' --norc
opzione può essere utilizzata per inibire questo comportamento e l' --rcfile
opzione può essere utilizzata per forzare la lettura di un altro file, ma né rshd
né in sshd
generale né invocare la shell con tali opzioni o consentirne la specifica.
Esempio
Inserire quanto segue all'inizio di un telecomando .bashrc
. (Se .bashrc
fornito da .profile
o .bash_profile
, disabilitalo temporaneamente durante il test):
echo bashrc
fun()
{
echo functions work
}
Esegui i seguenti comandi localmente:
$ ssh remote_host 'echo $- $0'
bashrc
hBc bash
- No
i
in $-
indica che la shell non è interattiva .
- Nessun leader
-
nel $0
indica che la shell non è una shell di login .
Le funzioni della shell definite nel telecomando .bashrc
possono anche essere eseguite:
$ ssh remote_host fun
bashrc
functions work
Ho notato che ~/.bashrc
viene fornito solo quando viene specificato un comando come argomento per ssh
. Questo ha senso: quando ssh
viene utilizzato per avviare una normale shell di accesso .profile
o .bash_profile
viene eseguito (e .bashrc
viene fornito solo se esplicitamente fatto da uno di questi file).
Il vantaggio principale che posso vedere per aver .bashrc
ottenuto quando si esegue un comando remoto (non interattivo) è che le funzioni della shell possono essere eseguite. Tuttavia, la maggior parte dei comandi in un tipico .bashrc
sono rilevanti solo in una shell interattiva, ad esempio gli alias non vengono espansi a meno che la shell non sia interattiva.
I trasferimenti di file remoti possono fallire
Questo di solito non è un problema quando rsh
o ssh
vengono utilizzati per avviare una shell di accesso interattivo o quando vengono utilizzate shell non interattive per eseguire comandi. Tuttavia, può essere un problema per i programmi come rcp
, scp
e sftp
che utilizzano shell remote per trasferire dati.
Si scopre che la shell predefinita dell'utente remoto (come Bash) viene avviata implicitamente quando si utilizza il scp
comando. Non c'è menzione di questo nella pagina man - solo una menzione che scp
usa ssh
per il suo trasferimento di dati. Ciò ha la conseguenza che se .bashrc
contiene comandi che stampano sull'output standard, i trasferimenti di file falliranno , ad esempio
scp fallirà senza errori .
Vedi anche questo relativo rapporto sui bug di Red Hat di 15 anni fa, scp si interrompe quando c'è un comando echo in / etc / bashrc (che alla fine è stato chiuso come WONTFIX
).
Perché scp
e sftp
fallire
SCP (Secure copy) e SFTP (Secure File Transfer Protocol) hanno i propri protocolli per le estremità locali e remote per scambiare informazioni sui file che vengono trasferiti. Qualsiasi testo imprevisto dall'estremità remota viene (erroneamente) interpretato come parte del protocollo e il trasferimento non riesce. Secondo una FAQ dal Snail Book
Ciò che spesso accade, però, è che ci sono dichiarazioni in entrambi il sistema o file di avvio della shell per utente sul server ( .bashrc
, .profile
,
/etc/csh.cshrc
, .login
, ecc), che in uscita messaggi di testo sul login, deve essere letto dagli esseri umani (come fortune
, echo "Hi there!"
, eccetera.).
Tale codice dovrebbe produrre output solo su accessi interattivi, quando è presente un
tty
input standard. Se non esegue questo test, inserirà questi messaggi di testo in cui non appartengono: in questo caso, inquinando il flusso di protocollo tra scp2
/ sftp
e sftp-server
.
Il motivo per cui i file di avvio della shell sono rilevanti è che sshd
utilizza la shell dell'utente all'avvio di qualsiasi programma per conto dell'utente
(utilizzando ad esempio / bin / sh -c "comando"). Questa è una tradizione Unix e presenta vantaggi:
- Le normali impostazioni dell'utente (alias dei comandi, variabili di ambiente, umask, ecc.) Sono attive quando vengono eseguiti i comandi remoti.
- La pratica comune di impostare la shell di un account su / bin / false per disabilitarlo impedirà al proprietario di eseguire qualsiasi comando, nel caso in cui l'autenticazione dovesse continuare accidentalmente per qualche motivo.
Dettagli del protocollo SCP
Per coloro che sono interessati ai dettagli su come funziona SCP, ho trovato informazioni interessanti in Come funziona il protocollo SCP che include dettagli su Esecuzione di scp con profili di shell loquace sul lato remoto? :
Ad esempio, ciò può accadere se lo aggiungi al tuo profilo shell sul sistema remoto:
eco ""
Perché si blocca e basta? Ciò deriva dal modo in cui scp
in modalità sorgente attende la conferma del primo messaggio di protocollo. Se non è 0 binario, si aspetta che sia una notifica di un problema remoto e attende che più caratteri formino un messaggio di errore fino all'arrivo della nuova riga. Dal momento che non hai stampato un'altra nuova riga dopo la prima, il tuo locale scp
rimane in loop, bloccato read(2)
. Nel frattempo, dopo l'elaborazione del profilo della shell sul lato remoto, è scp
stata avviata la modalità sink, che si blocca anche in read(2)
attesa di uno zero binario che indica l'inizio del trasferimento dei dati.
Conclusione / TLDR
La maggior parte delle istruzioni in un tipico .bashrc
sono utili solo per una shell interattiva, non quando si eseguono comandi remoti con rsh
o ssh
. Nella maggior parte di tali situazioni, l'impostazione di variabili di shell, alias e definizione di funzioni non è desiderata e la stampa di qualsiasi testo su standard out è attivamente dannosa se il trasferimento di file mediante programmi come scp
o sftp
. Uscire dopo aver verificato che la shell corrente non sia interattiva è il comportamento più sicuro per .bashrc
.