Questa è una domanda che avrei pubblicato qui qualche settimana fa. Come terdon , ho capito che a .bashrcproviene solo per shell Bash interattive, quindi non dovrebbe essere necessario .bashrcverificare 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 ~/.bashrccomandi 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' --norcopzione può essere utilizzata per inibire questo comportamento e l' --rcfileopzione può essere utilizzata per forzare la lettura di un altro file, ma né rshdné in sshdgenerale né invocare la shell con tali opzioni o consentirne la specifica.
Esempio
Inserire quanto segue all'inizio di un telecomando .bashrc. (Se .bashrcfornito da .profileo .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
iin $-indica che la shell non è interattiva .
- Nessun leader
-nel $0indica che la shell non è una shell di login .
Le funzioni della shell definite nel telecomando .bashrcpossono anche essere eseguite:
$ ssh remote_host fun
bashrc
functions work
Ho notato che ~/.bashrcviene fornito solo quando viene specificato un comando come argomento per ssh. Questo ha senso: quando sshviene utilizzato per avviare una normale shell di accesso .profileo .bash_profileviene eseguito (e .bashrcviene fornito solo se esplicitamente fatto da uno di questi file).
Il vantaggio principale che posso vedere per aver .bashrcottenuto 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 .bashrcsono 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 rsho sshvengono 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, scpe sftpche utilizzano shell remote per trasferire dati.
Si scopre che la shell predefinita dell'utente remoto (come Bash) viene avviata implicitamente quando si utilizza il scpcomando. Non c'è menzione di questo nella pagina man - solo una menzione che scpusa sshper il suo trasferimento di dati. Ciò ha la conseguenza che se .bashrccontiene 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é scpe sftpfallire
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
ttyinput 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/ sftpe 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 scpin 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 scprimane in loop, bloccato read(2). Nel frattempo, dopo l'elaborazione del profilo della shell sul lato remoto, è scpstata 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 .bashrcsono utili solo per una shell interattiva, non quando si eseguono comandi remoti con rsho 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 scpo sftp. Uscire dopo aver verificato che la shell corrente non sia interattiva è il comportamento più sicuro per .bashrc.