¿Por qué / bin / sh se comporta de manera diferente a / bin / bash incluso si uno apunta al otro?

Mientras estaba jugando en mi caparazón investigando la respuesta a esta pregunta , noté que, aunque /bin/sh apuntaba a /bin/bash en mi sistema, los dos comandos se comportan de manera diferente. En primer lugar, la salida de

 ls -lh /bin/sh 

es:

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

Sin embargo, invocando el siguiente comando a través de /bin/sh :

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

devuelve este error:

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

Mientras ejecuta el mismo comando a través de /bin/bash :

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

se ejecuta con éxito, aquí está el resultado:

 This should be on stderr 

Como referencia, aquí está el contenido de 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 

¿Por qué las dos invocaciones se comportan de manera diferente?

bash mira el valor de $argv[0] (bash se implementa en C) para determinar cómo se invocó.

Su comportamiento cuando se invoca como sh se documenta en el manual :

Si Bash se invoca con el nombre sh , intenta imitar el comportamiento de inicio de las versiones históricas de sh más fielmente posible, al mismo tiempo que se ajusta al estándar POSIX.

Cuando se invoca como un shell de inicio de sesión interactivo o como un shell no interactivo con la opción -login , primero intenta leer y ejecutar comandos desde /etc/profile y ~/.profile , en ese orden. La opción --noprofile se puede usar para nhibernate este comportamiento. Cuando se invoca como un shell interactivo con el nombre sh , Bash busca la variable ENV , expande su valor si está definida y usa el valor expandido como el nombre de un archivo para leer y ejecutar. Como un intérprete de comandos invocado como sh no intenta leer y ejecutar comandos desde ningún otro archivo de inicio, la opción --rcfile no tiene ningún efecto. Un shell no interactivo invocado con el nombre sh no intenta leer ningún otro archivo de inicio.

Cuando se invoca como sh , Bash entra al modo POSIX después de leer los archivos de inicio

Hay una larga lista (actualmente 46 elementos) de cosas que cambian cuando bash está en modo POSIX, documentado aquí .

(El modo POSIX es probablemente útil sobre todo como una forma de probar scripts para portabilidad a shells que no son bash ).

Incidentalmente, los progtwigs que cambian su comportamiento dependiendo del nombre bajo el cual fueron invocados son bastante comunes. Algunas versiones de grep , fgrep y egrep se implementan como un único ejecutable (aunque GNU grep no lo hace). view es típicamente un enlace simbólico a vi o vim ; invocándolo como view hace que se abra en modo de solo lectura. El sistema Busybox incluye una cantidad de comandos individuales que son todos enlaces simbólicos al ejecutable master busybox .

Invocar bash como sh hace que ingrese al modo posix después de leer los archivos de inicio que normalmente leería (a diferencia de los archivos de inicio que un POSIX sh leería). Bash tiene muchos modos de invocación diferentes. Puede obtener más información sobre estos modos en la sección INVOCATION del manual. Aquí hay algunos detalles sobre el modo POSIX.

Modo POSIX

Este modo significa que bash intentará, en varios grados, ajustarse a las expectativas de POSIX. Como se explica aquí , bash tiene algunas invocaciones diferentes para este modo, con implicaciones ligeramente diferentes:

  1. sh : Bash ingresa al modo POSIX después de leer los archivos de inicio.
  2. bash --posix : Bash ingresa al modo POSIX antes de leer los archivos de inicio.
  3. set -o posix : Bash cambia al modo POSIX.
  4. POSIXLY_CORRECT : si esta variable está en el entorno cuando se inicia bash, el shell ingresa al modo posix antes de leer los archivos de inicio, como bash --posix . Si se establece mientras bash se está ejecutando, como set -o posix .

Del manual de referencia de Bash :

Si Bash se invoca con el nombre sh, intenta imitar el comportamiento de inicio de las versiones históricas de sh lo más fielmente posible, al mismo tiempo que se ajusta al estándar POSIX.

Porque el bash binary comprueba cómo se invocó (a través de argv[0] ) y entra en un modo de compatibilidad si se está ejecutando como sh .