Почему /bin/sh ведет себя иначе, чем /bin/bash, даже если один указывает на другой?

Пока я играл в своей оболочке, изучая ответ на этот вопрос, я заметил, что, хотя /bin/sh указывал на /bin/bash в моей системе две команды ведут себя по-разному. Прежде всего, вывод

ls -lh /bin/sh

является:

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

Тем не менее, вызывая следующую команду через /bin/sh:

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

возвращает эту ошибку:

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

Во время выполнения той же команды через /bin/bash:

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

выполняется успешно, вот вывод:

This should be on stderr

Для справки, вот содержание 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

Почему два вызова ведут себя по-разному?

4 ответа

Решение

bash смотрит на стоимость $argv[0] (bash реализован в C), чтобы определить, как он был вызван.

Его поведение, когда вызывается как sh задокументировано в руководстве:

Если Bash вызывается с именем sh, он пытается имитировать поведение при запуске исторических версий sh настолько близко, насколько это возможно, и в то же время соответствует стандарту POSIX.

Когда вызывается как интерактивная оболочка входа или как неинтерактивная оболочка с -login вариант, он сначала пытается читать и выполнять команды из /etc/profile а также ~/.profile, в этой последовательности. --noprofile опция может быть использована для подавления этого поведения. Когда вызывается как интерактивная оболочка с именем shБаш ищет переменную ENV, расширяет свое значение, если оно определено, и использует расширенное значение в качестве имени файла для чтения и выполнения. Поскольку оболочка вызывается как sh не пытается читать и выполнять команды из любых других файлов запуска, --rcfile опция не имеет никакого эффекта. Неинтерактивная оболочка, вызываемая с именем sh не пытается читать любые другие файлы запуска.

Когда вызывается как shBash переходит в режим POSIX после чтения файлов запуска

Есть длинный список (в настоящее время 46 пунктов) вещей, которые меняются, когда bash находится в режиме POSIX, задокументировано здесь.

(Режим POSIX, вероятно, полезен в основном как способ проверки скриптов на переносимостьbash снаряды.)

Кстати, программы, которые меняют свое поведение в зависимости от имени, под которым они были вызваны, довольно распространены. Некоторые версии grep, fgrep, а также egrep реализованы как один исполняемый файл (хотя GNU grep не делает этого). view обычно является символической ссылкой на vi или же vim; ссылаясь на это как view вызывает открытие в режиме только для чтения. Система Busybox включает в себя ряд отдельных команд, которые все являются символическими ссылками на мастер busybox исполняемый файл.

Вызывая bash as sh заставляет его войти в режим posix после чтения файлов запуска, которые он обычно читает (в отличие от файлов запуска, которые читает POSIX sh). Bash имеет много различных режимов вызова. Вы можете узнать об этих режимах из INVOCATION раздел руководства. Вот некоторые подробности о режиме POSIX.

Режим POSIX

Этот режим означает, что bash будет пытаться в различной степени соответствовать ожиданиям POSIX. Как объяснено здесь, bash имеет несколько разных вызовов для этого режима, с немного другими последствиями:

  1. sh: Bash переходит в режим POSIX после чтения файлов запуска.
  2. bash --posix: Bash входит в режим POSIX перед чтением файлов запуска.
  3. set -o posix: Bash переключается в режим POSIX.
  4. POSIXLY_CORRECT: Если эта переменная находится в среде, когда запускается bash, оболочка переходит в режим posix перед чтением файлов запуска, например bash --posix, Если он установлен во время работы bash, например set -o posix,

Из справочного руководства Bash:

Если Bash вызывается с именем sh, он пытается максимально близко имитировать поведение при запуске исторических версий sh, при этом также соответствует стандарту POSIX.

Поскольку bash двоичные проверки, как это было вызвано (через argv[0]) и входит в режим совместимости, если он запускается как sh,

Другие вопросы по тегам