GNU/Linux >> Linux Esercitazione >  >> Linux

Perché Bashrc controlla se la shell corrente è interattiva?

Sulla mia installazione di Arch, /etc/bash.bashrc e /etc/skel/.bashrc contengono queste righe:

# If not running interactively, don't do anything
[[ $- != *i* ]] && return

Su Debian, /etc/bash.bashrc ha:

# If not running interactively, don't do anything
[ -z "$PS1" ] && return

E /etc/skel/.bashrc :

# If not running interactively, don't do anything
case $- in
    *i*) ;;
      *) return;;
esac

Secondo man bash , tuttavia, le shell non interattive non leggono nemmeno questi file:

   When  bash  is  started  non-interactively,  to run a shell script, for
   example, it looks for the variable BASH_ENV in the environment, expands
   its  value if it appears there, and uses the expanded value as the name
   of a file to read and execute.  Bash behaves as if the  following  com‐
   mand were executed:
          if [ -n "$BASH_ENV" ]; then . "$BASH_ENV"; fi
   but  the value of the PATH variable is not used to search for the file‐
   name.

Se ho capito bene, il *.bashrc i file verranno letti solo se BASH_ENV è impostato per puntare a loro. Questo è qualcosa che non può accadere per caso e accadrà solo se qualcuno ha impostato esplicitamente la variabile di conseguenza.

Ciò sembra interrompere la possibilità di avere script come fonte di .bashrc di un utente automaticamente impostando BASH_ENV , qualcosa che potrebbe tornare utile. Dato che bash non leggerà mai questi file quando viene eseguito in modo non interattivo a meno che non venga esplicitamente detto di farlo, perché l'impostazione predefinita *bashrc i file non lo consentono?

Risposta accettata:

Questa è una domanda che avrei postato qui qualche settimana fa. Come terdon , ho capito che un .bashrc viene fornito solo per shell Bash interattive, quindi non dovrebbe essere necessario .bashrc per verificare se è in esecuzione in una shell interattiva. Confusamente, tutti le distribuzioni che uso (Ubuntu, RHEL e Cygwin) avevano un qualche tipo di controllo (test $- o $PS1 ) per garantire che la shell corrente sia interattiva. Non mi piace la programmazione cargo cult, quindi ho cercato di capire lo scopo di questo codice nel mio .bashrc .

Bash ha una custodia speciale per le shell remote

Dopo aver studiato il problema, ho scoperto che shell remote vengono trattati in modo diverso. Mentre le shell Bash non interattive normalmente non eseguono ~/.bashrc comandi all'avvio, si verifica un caso speciale quando la shell viene richiamata dal demone della shell remota:

Bash tenta di determinare quando viene eseguito con il suo input standard
connesso a una connessione di rete, come quando viene eseguito dal demone della shell remota
, di solito rshd o il demone della shell sicura 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 . Il --norc l'opzione può essere usata per inibire questo comportamento,
e il --rcfile l'opzione può essere utilizzata per forzare la lettura di un altro file, ma
rshdsshd generalmente richiama la shell con queste opzioni o
consenti che vengano specificate.

Esempio

Inserisci quanto segue all'inizio di un .bashrc remoto . (Se .bashrc proviene da .profile o .bash_profile , disabilitalo temporaneamente durante il test):

echo bashrc
fun()
{
    echo functions work
}

Esegui i seguenti comandi in locale:

$ ssh remote_host 'echo $- $0'
bashrc
hBc bash
  • Nessun i in $- indica che la shell è non interattiva .
  • Nessun - iniziale in $0 indica che la shell non è una shell di accesso .

Funzioni della shell definite nel .bashrc remoto può anche essere eseguito:

$ ssh remote_host fun
bashrc
functions work

Ho notato che il ~/.bashrc è solo originato quando un comando viene specificato come argomento per ssh . Questo ha senso:quando ssh viene utilizzato per avviare una normale shell di accesso, .profile o .bash_profile vengono eseguiti (e .bashrc viene originato solo se esplicitamente fatto da uno di questi file).

Correlati:Php:corrente — Restituisce l'elemento corrente in un array

Il vantaggio principale che posso vedere nell'avere .bashrc originato durante l'esecuzione di 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 non riuscire

Questo di solito non è un problema quando rsh o ssh vengono utilizzati per avviare una shell di accesso interattiva o quando vengono utilizzate shell non interattive per eseguire comandi. Tuttavia, può essere un problema per programmi come rcp , scp e sftp che utilizzano shell remote per il trasferimento dei dati.

Si scopre che la shell predefinita dell'utente remoto (come Bash) viene avviata implicitamente quando si utilizza scp comando. Non c'è alcuna menzione di questo nella pagina man, solo una menzione che scp usa ssh per il suo trasferimento di dati. Questo ha la conseguenza che se il .bashrc contiene tutti i comandi che stampano sullo standard output, i trasferimenti di file non andranno a buon fine , ad esempio, scp ha esito negativo senza errori.

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 lo scambio di informazioni sui file trasferiti. Qualsiasi testo imprevisto dall'estremità remota viene interpretato (erroneamente) come parte del protocollo e il trasferimento non riesce. Secondo una FAQ dello Snail Book

Ciò che accade spesso, tuttavia, è che ci sono istruzioni nel sistema
o nei file di avvio della shell per utente sul server (.bashrc , .profile , /etc/csh.cshrc , .login , ecc.) che generano messaggi di testo all'accesso,
destinati ad essere letti dagli esseri umani (come fortune , echo "Hi there!" , ecc.).

Tale codice dovrebbe produrre output solo su accessi interattivi, quando è presente un tty allegato allo standard input. Se non effettua questo test,
inserirà questi sms dove 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 quando avvia programmi per conto dell'utente (usando ad esempio /bin/sh -c "comando"). Questa è una tradizione Unix e presenta
vantaggi:

  • La configurazione abituale dell'utente (alias dei comandi, variabili di ambiente, umask,
    ecc.) è attiva quando vengono eseguiti i comandi remoti.
  • La pratica comune di impostare la shell di un account su /bin/false per disabilitare
    impedirà al proprietario di eseguire qualsiasi comando, nel caso in cui l'autenticazione
    dovesse ancora riuscire 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 Eseguire scp con profili di shell loquaci sul lato remoto? :

Ad esempio, ciò può accadere se lo aggiungi al tuo profilo shell sul
sistema remoto:

eco “”

Perché si blocca? Questo deriva dal modo in cui scp nella fonte mode
attende la conferma del primo messaggio di protocollo. Se non è binario
0, 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. Poiché
non hai stampato un'altra nuova riga dopo la prima, il tuo scp locale solo
rimane in loop, bloccato su read(2) . Nel frattempo, dopo che il profilo della shell
è stato elaborato sul lato remoto, scp in modalità sink è stato avviato,
che si blocca anche su read(2) , in attesa di uno zero binario che denoti 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 queste situazioni, non si desidera impostare variabili shell, alias e definire funzioni e stampare qualsiasi testo standard out è attivamente dannoso se si trasferiscono file utilizzando programmi come scp o sftp . Uscire dopo aver verificato che la shell corrente non sia interattiva è il comportamento più sicuro per .bashrc .


Linux
  1. Fai calcoli nella shell Linux con GNU bc

  2. Limita Alt+Tab al monitor corrente nella shell di GNOME

  3. Lo scopo di .bashrc e come funziona?

  4. Come verificare se una shell è login/interactive/batch?

  5. Perché l'utente root ha bisogno dell'autorizzazione Sudo?

Come installare Fish, la shell interattiva amichevole, in Linux

Perché $shlvl inizia al livello 2 nelle shell non di accesso ma al livello 1 nelle shell di accesso in Rhel 7?

Perché nessuno usa la vera shell Bourne come /bin/sh?

Perché la Regex in Bash funziona solo se è una variabile e non direttamente??

Cosa significa la sintassi |&nel linguaggio della shell?

Perché il bit setuid funziona in modo incoerente?