Perché / bin / sh si comporta diversamente con / bin / bash anche se uno punta all’altro?

Mentre stavo giocando nel mio guscio indagando sulla risposta a questa domanda , ho notato che, anche se /bin/sh stava puntando a /bin/bash sul mio sistema, i due comandi si comportano diversamente. Prima di tutto, l’output di

 ls -lh /bin/sh 

è:

 lrwxrwxrwx 1 root root 4 Apr 22 2013 /bin/sh -> bash* 

Tuttavia, richiamando il seguente comando tramite /bin/sh :

 /bin/sh -c "script.sh 2> >( grep -v FILTER 2>&1 )" 

restituisce questo errore:

 /bin/sh: -c: line 0: syntax error near unexpected token '>' /bin/sh: -c: line 0: 'script.sh 2> >( grep -v FILTER 2>&1 )' 

Mentre si esegue lo stesso comando tramite /bin/bash :

 /bin/bash -c "script.sh 2> >( grep -v FILTER 2>&1 )" 

esegue con successo, ecco l’output:

 This should be on stderr 

Per riferimento, ecco il contenuto di script.sh :

 #!/bin/sh echo "FILTER: This should be filtered out" 1>&2 echo "This should be on stderr" 1>&2 echo "FILTER: This should be filtered out" 1>&2 

Perché le due invocazioni si comportano diversamente?

bash esamina il valore di $argv[0] (bash è implementato in C) per determinare come è stato richiamato.

Il suo comportamento quando invocato come sh è documentato nel manuale :

Se Bash viene invocato con il nome sh , prova a simulare il comportamento di avvio delle versioni storiche di sh più fedelmente ansible, pur conformandosi allo standard POSIX.

Quando viene invocato come shell di login intertriggers, o come shell non intertriggers con l’opzione -login , tenta innanzitutto di leggere ed eseguire comandi da /etc/profile e ~/.profile , in questo ordine. L’opzione --noprofile può essere utilizzata per inibire questo comportamento. Quando invocato come shell intertriggers con il nome sh , Bash cerca la variabile ENV , espande il suo valore se è definito e utilizza il valore espanso come nome di un file da leggere ed eseguire. Poiché una shell invocata come sh non tenta di leggere ed eseguire comandi da altri file di avvio, l’opzione --rcfile non ha alcun effetto. Una shell non intertriggers invocata con il nome sh non tenta di leggere altri file di avvio.

Quando invocato come sh , Bash entra in modalità POSIX dopo la lettura dei file di avvio

C’è una lunga lista (attualmente 46 articoli) di cose che cambiano quando bash è in modalità POSIX, documentato qui .

(La modalità POSIX è probabilmente utile soprattutto come metodo per testare gli script per la portabilità delle bash non bash .)

Per inciso, i programmi che cambiano il loro comportamento a seconda del nome con cui sono stati invocati sono abbastanza comuni. Alcune versioni di grep , fgrep ed egrep sono implementate come un singolo eseguibile (sebbene GNU grep non lo faccia). view è in genere un collegamento simbolico a vi o vim ; invocarlo come view provoca l’apertura in modalità di sola lettura. Il sistema Busybox include un numero di singoli comandi che sono tutti collegamenti simbolici all’eseguibile della busybox principale.

Invocare bash come sh fa in modo che entri in modalità posix dopo aver letto i file di avvio che normalmente leggeva (al contrario dei file di avvio che avrebbe letto un POSIX sh). Bash ha molte modalità di chiamata diverse. Puoi scoprire queste modalità dalla sezione INVOCATION del manuale. Ecco alcuni dettagli sulla modalità POSIX.

Modalità POSIX

Questa modalità significa che bash proverà, in vari gradi, a conformarsi alle aspettative POSIX. Come spiegato qui , bash ha alcune invocazioni diverse per questa modalità, con implicazioni leggermente diverse:

  1. sh : Bash entra in modalità POSIX dopo aver letto i file di avvio.
  2. bash --posix : Bash entra in modalità POSIX prima di leggere i file di avvio.
  3. set -o posix : Bash passa in modalità POSIX.
  4. POSIXLY_CORRECT : se questa variabile si trova nell’ambiente all’avvio di bash, la shell entra in modalità posix prima di leggere i file di avvio, come bash --posix . Se è impostato mentre bash è in esecuzione, come set -o posix .

Dal manuale di riferimento di Bash :

Se Bash viene invocato con il nome sh, prova a simulare il comportamento di avvio delle versioni storiche di sh il più fedelmente ansible, pur conformandosi allo standard POSIX.

Perché il binario di bash controlla come è stato invocato (tramite argv[0] ) ed entra in una modalità di compatibilità se viene eseguito come sh .