Почему /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
не пытается читать любые другие файлы запуска.Когда вызывается как
sh
Bash переходит в режим 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 имеет несколько разных вызовов для этого режима, с немного другими последствиями:
sh
: Bash переходит в режим POSIX после чтения файлов запуска.bash --posix
: Bash входит в режим POSIX перед чтением файлов запуска.set -o posix
: Bash переключается в режим POSIX.POSIXLY_CORRECT
: Если эта переменная находится в среде, когда запускается bash, оболочка переходит в режим posix перед чтением файлов запуска, напримерbash --posix
, Если он установлен во время работы bash, напримерset -o posix
,
Из справочного руководства Bash:
Если Bash вызывается с именем sh, он пытается максимально близко имитировать поведение при запуске исторических версий sh, при этом также соответствует стандарту POSIX.
Поскольку bash
двоичные проверки, как это было вызвано (через argv[0]
) и входит в режим совместимости, если он запускается как sh
,