Bash и POSIX
6.11.1 Что такое POSIX?
POSIX — это название семейства стандартов, основанных на Unix. В стандарт входит ряд служб, инструментов и функций Unix — от базовых системных вызовов и функций библиотеки C до распространённых приложений и инструментов системного администрирования и управления.
Стандарт POSIX Shell and Utilities первоначально разработала рабочая группа IEEE 1003.2 (POSIX.2). Первое издание стандарта 1003.2 было опубликовано в 1992 году. Эта группа объединилась с первоначальной рабочей группой IEEE 1003.1; в настоящее время стандарт поддерживает группа Austin (совместная рабочая группа IEEE, The Open Group и ISO/IEC SC22/WG15). Сегодня Shell and Utilities — это том из набора документов, составляющих IEEE Std 1003.1-2024, поэтому прежний POSIX.2 (от 1992 года) теперь является частью действующего объединённого стандарта POSIX.
Том Shell and Utilities посвящён интерфейсу командного интерпретатора и служебным программам, которые обычно запускаются из командной строки или другими программами. Стандарт доступен в интернете бесплатно по адресу https://pubs.opengroup.org/onlinepubs/9799919799/utilities/contents.html.
Bash учитывает аспекты поведения оболочки, определённые томом POSIX Shell and Utilities. Разумеется, стандартизирован язык команд оболочки, включая основные конструкции управления потоком и выполнения программ, перенаправление ввода-вывода и конвейеры, обработку аргументов, подстановку переменных и экранирование.
Специальные встроенные команды, которые должны быть реализованы в составе оболочки для обеспечения требуемой функциональности, определены как часть оболочки; к ним относятся, например, eval и export. Другие утилиты описаны в разделах POSIX, не посвящённых оболочке, но обычно (а в некоторых случаях обязательно) реализуются как встроенные команды, например read и test. POSIX также определяет некоторые аспекты интерактивного поведения оболочки, включая управление заданиями и редактирование командной строки. Стандартизированы только команды редактирования строк в стиле vi; команды редактирования в стиле Emacs не включили из-за возражений.
6.11.2 Режим POSIX в Bash
Хотя Bash реализует спецификацию оболочки POSIX, в некоторых случаях поведение Bash по умолчанию отличается от спецификации. Режим POSIX Bash изменяет поведение в этих случаях, чтобы оно точнее соответствовало стандарту.
Если запустить Bash с параметром командной строки --posix или выполнить команду ‘set -o posix’ во время работы Bash, он будет точнее соответствовать стандарту POSIX: поведение Bash изменится и будет соответствовать требованиям POSIX в тех случаях, где поведение Bash по умолчанию отличается.
При запуске в качестве sh Bash переходит в режим POSIX после чтения файлов запуска.
Ниже перечислены изменения, действующие в режиме POSIX:
- Bash гарантирует, что переменная
POSIXLY_CORRECTустановлена. - Bash читает и выполняет файлы запуска POSIX (
$ENV), а не обычные файлы Bash (см. Файлы запуска Bash. - Подстановка псевдонимов всегда включена, в том числе в неинтерактивных оболочках.
- Зарезервированные слова, встречающиеся в контексте, где распознаются зарезервированные слова, не подвергаются подстановке псевдонимов.
- Подстановка псевдонимов выполняется при первоначальном разборе подстановки команды. В режиме по умолчанию (не POSIX) она обычно откладывается, если включена, до выполнения подстановки команды. Это означает, что при подстановке команды не будут подставляться псевдонимы, определённые после её первоначального разбора (например, при определении функции).
- Зарезервированное слово
timeможно использовать самостоятельно в качестве простой команды. В таком виде оно выводит статистику времени для оболочки и завершившихся дочерних процессов. Формат сведений о времени задаётся переменнойTIMEFORMAT. - Анализатор не распознаёт
timeкак зарезервированное слово, если следующий токен начинается с ‘-’. - При разборе и подстановке конструкции ${…}, находящейся внутри двойных кавычек, одинарные кавычки больше не являются специальными символами и не могут использоваться для экранирования закрывающей фигурной скобки или другого специального символа, если только оператор не относится к операторам удаления шаблонов. В этом случае одинарные кавычки не обязательно должны образовывать пару.
- Операторы перенаправления не выполняют подстановку имён файлов для слова в перенаправлении, если оболочка не является интерактивной.
- Операторы перенаправления не выполняют разделение слов для слова в перенаправлении.
- Имена функций не могут совпадать с именами специальных встроенных команд POSIX.
- Подстановка тильды выполняется только для присваиваний, предшествующих имени команды, а не для всех операторов присваивания в строке.
- Хотя косвенное обращение к переменным доступно, его нельзя применять к специальным параметрам ‘#’ и ‘?’.
- При подстановке специального параметра ‘*’ в контексте шаблона, когда подстановка заключена в двойные кавычки,
$*не рассматривается как заключённый в двойные кавычки. - Символ двойной кавычки (‘"’) обрабатывается особым образом, если он встречается в подстановке команды с обратными кавычками внутри тела расширяемого документа here-doc. Это означает, например, что обратная косая черта перед двойной кавычкой экранирует её и удаляется.
- Подстановки команд не устанавливают специальный параметр ‘?’. Код завершения простой команды без слова команды по-прежнему равен коду завершения последней подстановки команды, выполненной при вычислении присваиваний переменных и перенаправлений в этой команде, но это происходит только после всех присваиваний и перенаправлений.
- Буквальные тильды, стоящие первыми символами элементов переменной
PATH, не подставляются, как описано выше в разделе Подстановка тильды. - При поиске команд специальные встроенные команды POSIX имеют приоритет перед функциями оболочки, в том числе при выводе командами
typeиcommand. - Даже если функция оболочки, имя которой содержит косую черту, была определена до перехода в режим POSIX, оболочка не будет выполнять функцию, имя которой содержит одну или несколько косых черт.
- Если команда из хеш-таблицы больше не существует, Bash повторно выполнит поиск в
$PATH, чтобы найти её новое расположение. Это поведение также можно включить командой ‘shopt -s checkhash’. - Bash не будет добавлять в хеш-таблицу команду без установленного бита выполнения, даже если она возвращается в качестве последнего возможного результата поиска
$PATH. - Сообщение, выводимое кодом управления заданиями и встроенными командами при завершении задания с ненулевым статусом, — ‘Done(status)’.
- Сообщение, выводимое кодом управления заданиями и встроенными командами при приостановке задания, — ‘Stopped(signame)’, где signame — это, например,
SIGTSTP. - Если оболочка интерактивна, Bash не выводит уведомления о заданиях между выполнением команд в списках, разделённых символом ‘;’ или переводом строки. Неинтерактивные оболочки выводят сообщения о состоянии после завершения команды переднего плана в списке.
- Если оболочка интерактивна, Bash ждёт следующего приглашения, прежде чем вывести состояние фонового задания, состояние которого изменилось, или задания переднего плана, завершившегося из-за сигнала. Неинтерактивные оболочки выводят сообщения о состоянии после завершения задания переднего плана.
- Bash окончательно удаляет задания из таблицы заданий после уведомления пользователя об их завершении с помощью встроенных команд
waitилиjobs. Задание удаляется из списка заданий после уведомления пользователя о завершении, однако его статус по-прежнему доступен черезwait, если командеwaitпередан аргумент PID. - В режиме редактирования
viкоманда ‘v’ напрямую запускает редакторvi, не проверяя$VISUALи$EDITOR. - При раскрытии приглашения включается раскрытие POSIX
PS1иPS2: ‘!’ заменяется номером в истории, а ‘!!’ — на ‘!’. Bash выполняет подстановку параметров для значенийPS1иPS2независимо от состояния параметраpromptvars. - Файл истории по умолчанию — ~/.sh_history (это значение, которое оболочка по умолчанию присваивает переменной
$HISTFILE). - Символ ‘!’ не запускает подстановку из истории внутри строки в двойных кавычках, даже если включён параметр
histexpand. - При выводе определений функций оболочки (например, командой
type) Bash не выводит зарезервированное словоfunction, если в этом нет необходимости. - Неинтерактивные оболочки завершают работу, если синтаксическая ошибка в арифметическом выражении приводит к недопустимому выражению.
- Неинтерактивные оболочки завершают работу при ошибке подстановки параметра.
- Если специальная встроенная команда POSIX возвращает статус ошибки, неинтерактивная оболочка завершается. К фатальным относятся ошибки, перечисленные в стандарте POSIX, например передача недопустимых параметров, ошибки перенаправления, ошибки присваивания переменных в присваиваниях перед именем команды и т. д.
- Неинтерактивная оболочка завершается с ошибочным статусом, если возникает ошибка присваивания переменной и за операторами присваивания не следует имя команды. Например, ошибка присваивания возникает при попытке присвоить значение переменной, доступной только для чтения.
- Неинтерактивная оболочка завершается с ошибочным статусом, если ошибка присваивания переменной возникает в операторе присваивания перед специальной встроенной командой, но не перед какой-либо другой простой командой. Для любой другой простой команды оболочка прерывает выполнение этой команды, а выполнение продолжается на верхнем уровне («оболочка не должна выполнять дальнейшую обработку команды, в которой произошла ошибка»).
- Неинтерактивная оболочка завершается с ошибочным статусом, если переменная итерации в операторе
forили переменная выбора в оператореselectдоступна только для чтения или имеет недопустимое имя. - Неинтерактивные оболочки завершают работу, если файл filename в
.filename не найден. - Неинтерактивные оболочки завершают работу при синтаксической ошибке в скрипте, прочитанном встроенными командами
.илиsource, либо в строке, обработанной встроенной командойeval. - Неинтерактивные оболочки завершают работу, если встроенные команды
export,readonlyилиunsetполучают аргумент, не являющийся допустимым идентификатором, и не работают с функциями оболочки. Эти ошибки приводят к завершению работы, поскольку это специальные встроенные команды. - Операторы присваивания перед специальными встроенными командами POSIX сохраняются в окружении оболочки после завершения встроенной команды.
- Встроенная команда
commandне препятствует встроенным командам, принимающим операторы присваивания в качестве аргументов, обрабатывать их как операторы присваивания; вне режима POSIX команды объявления теряют свойства обработки операторов присваивания, если перед ними указанаcommand. - Включение режима POSIX приводит к установке параметра
inherit_errexit, поэтому подоболочки, запускаемые для выполнения подстановок команд, наследуют значение параметра -e родительской оболочки. Если параметрinherit_errexitне включён, Bash сбрасывает параметр -e в таких подоболочках. - Включение режима POSIX приводит к установке параметра
shift_verbose, поэтому числовые аргументы командыshift, превышающие количество позиционных параметров, вызывают сообщение об ошибке. - Включение режима POSIX приводит к установке параметра
interactive_comments(см. Комментарии). - Встроенные команды
.иsourceне ищут файл-аргумент в текущем каталоге, если он не найден при поиске вPATH. - При выводе определений псевдонимов встроенная команда
aliasне добавляет в начало ‘alias ’, если не указан параметр -p. - Встроенная команда
bgиспользует требуемый формат для описания каждого задания, помещённого в фоновый режим; в нём не указывается, является ли задание текущим или предыдущим. - Если встроенная команда
cdвызвана в логическом режиме и путь, сформированный из$PWDи переданного в качестве аргумента имени каталога, не указывает на существующий каталог,cdзавершится ошибкой, а не переключится на физический режим. - Если встроенная команда
cdне может сменить каталог, поскольку длина пути, сформированного из$PWDи переданного в качестве аргумента имени каталога, после канонизации превышаетPATH_MAX, командаcdпопытается использовать переданное имя каталога. - Если включён параметр
xpg_echo, Bash не пытается интерпретировать аргументыechoкак параметры.echoвыводит каждый аргумент после преобразования escape-последовательностей. - Встроенные команды
exportиreadonlyвыводят результат в формате, требуемом POSIX. - При выводе списка истории встроенная команда
fcне указывает, изменялась ли запись истории. - Редактор по умолчанию, используемый командой
fc, —ed. -
fcсчитает лишние аргументы ошибкой, а не игнорирует их. - Если команде
fc -sпередано слишком много аргументов,fcвыводит сообщение об ошибке и возвращает ошибочный статус. - Команда ‘kill -l’ выводит имена всех сигналов в одну строку через пробел, без префикса ‘SIG’.
- Встроенная команда
killне принимает имена сигналов с префиксом ‘SIG’. - Встроенная команда
killвозвращает ошибочный статус, если какой-либо аргумент pid или задание недопустимы либо если не удаётся отправить указанный сигнал какому-либо из них. В режиме по умолчаниюkillвозвращает успешный статус, если сигнал удалось отправить хотя бы одному из указанных процессов. - Встроенная команда
printfиспользуетdouble(черезstrtod) для преобразования аргументов, соответствующих спецификаторам преобразования чисел с плавающей точкой, вместоlong double, если эта функция доступна. Модификатор длины ‘L’ заставляетprintfиспользоватьlong double, если эта функция доступна. - Встроенная команда
pwdпроверяет, совпадает ли выводимое значение с текущим каталогом, даже если её не просят проверять файловую систему с помощью параметра -P. - Встроенная команда
readможет быть прервана сигналом, для которого задан обработчик. Если Bash получает перехваченный сигнал во время выполненияread, запускается обработчик сигнала, аreadвозвращает код завершения больше 128. - Если встроенная команда
setвызвана без параметров, она не выводит имена и определения функций оболочки. - Если встроенная команда
setвызвана без параметров, она выводит значения переменных без кавычек, если только они не содержат метасимволы оболочки, даже если результат содержит непечатаемые символы. - При вычислении бинарных операторов ‘<’ и ‘>’ встроенная команда
testсравнивает строки с учётом текущей локали. - Унарный первичный оператор -t встроенной команды
testтребует аргумент. В исторических версияхtestв некоторых случаях аргумент был необязательным; Bash пытается поддерживать это для обратной совместимости. - Встроенная команда
trapвыводит имена сигналов без начальногоSIG. - Встроенная команда
trapне проверяет, может ли первый аргумент задавать сигнал, и не восстанавливает исходный способ обработки сигнала, если это так, за исключением случая, когда аргумент состоит только из цифр и является допустимым номером сигнала. Чтобы сбросить обработчик указанного сигнала и восстановить исходный способ обработки, следует указать ‘-’ в качестве первого аргумента. -
trap -pбез аргументов выводит сигналы, для которых задан SIG_DFL, и сигналы, игнорировавшиеся при запуске оболочки, а не только сигналы с заданными обработчиками. - Встроенные команды
typeиcommandне сообщают, что неисполняемый файл найден, хотя оболочка попытается выполнить такой файл, если это единственный файл с таким именем, найденный в$PATH. - Встроенная команда
ulimitиспользует размер блока 512 байт для параметров -c и -f. - Встроенная команда
unsetс указанным параметром -v возвращает фатальную ошибку при попытке удалить переменнуюreadonlyилиnon-unsettable, что приводит к завершению неинтерактивной оболочки. - При удалении переменной, указанной в операторе присваивания перед командой, встроенная команда
unsetтакже пытается удалить одноимённую переменную в текущей или предыдущей области видимости. Это реализует требуемое поведение: «если присвоенная переменная далее изменяется утилитой, изменения, внесённые утилитой, должны сохраняться». - Поступление
SIGCHLDпри установленном обработчике дляSIGCHLDне прерывает встроенную командуwaitи не заставляет её немедленно завершиться. Команда обработчика сигнала выполняется при завершении каждого дочернего процесса. - После того как встроенная команда
waitвозвращает статус завершившегося фонового процесса, Bash удаляет этот статус из списка таких статусов.
В Bash есть дополнительное поведение POSIX, которое по умолчанию не реализовано даже в режиме POSIX. В частности:
- POSIX требует побайтового разделения слов. То есть каждый байт в значении
IFSпотенциально может разделять слово, даже если этот байт является частью многобайтового символа вIFSили частью многобайтового символа в самом слове. Bash допускает многобайтовые символы в значенииIFS, рассматривая допустимый многобайтовый символ как единый разделитель, и не разделяет допустимый многобайтовый символ, даже если один из составляющих его байтов присутствует вIFS. Это трактовка POSIX 1560, дополнительно изменённая в соответствии с issue 1924. - Встроенная команда
fcиспользует$EDITORв качестве программы для редактирования записей истории, еслиFCEDITне задана, вместо того чтобы сразу выбиратьedпо умолчанию.fcиспользуетed, еслиEDITORне задана. - Как отмечалось выше, для полного соответствия встроенной команды
echoBash требует включить параметрxpg_echo.
Bash можно настроить так, чтобы он по умолчанию соответствовал POSIX, указав параметр --enable-strict-posix-default для configure при сборке (см. Необязательные возможности).
Copyright © 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc.
Licensed under the GNU Free Documentation License.
https://www.gnu.org/software/bash/manual/html_node/Bash-POSIX-Mode.html