.ONESHELL
— это специфичное для поставщика GNU расширение, которое не является переносимым и не является частью стандарта POSIX.
Причина, по которой этого нет в стандарте POSIX, скорее всего, заключается в том, что пока существует только одна реализация, которая его поддерживает.
Легче объяснить причину, по которой это не стандарт по умолчанию:
POSIX tries to standardize existing behavior and POSIX does not like to make existing original UNIX implementations being in conflict with the standard - except when a specific behavior can be seen as a clear design bug.
Первоначальная реализация make
Стюарта Фельдмана в 1977 году вызывала каждую строку из списка действий в отдельной оболочке, используя sh -ce cmdline
, и она стала основной для всех последующих make
реализаций.
Но даже реализация GNU (, рассматриваемая отдельно ), не лишена проблем, когда действует .ONESHELL
. Причина в том, что GNU make не устанавливает флаг оболочки -e
при вызове команд. Это приводит к тому, что многострочный сценарий оболочки, вызванный .ONESHELL
, не завершается при возникновении ошибки.
Помимо этого, я вижу мало пользы для.ONESHELL
:
Многострочные сценарии оболочки могут использоваться внутри make
с помощью обратной косой черты в последовательности новой строки в файлах make.
Аргумент производительности не применяется к современным make
реализациям, поскольку современные реализации стараются избегать вызова оболочки в случае, если командная строка не содержит метасимволов, специфичных для оболочки.
Моя реализация smake
даже реализует встроенную поддержку команды echo
в случае, если это первая команда в строке echo
, за которой следует только одна точка с запятой и простая другая команда. Это позволяет избежать необходимости вызывать оболочку более чем в 90% случаев.
Чтобы сократить обратную косую черту, мы будем использовать GNU sed
с включенным расширенным режимом регулярных выражений -E
. Кроме того, мы будем использовать скобки обратной ссылки, чтобы еще больше сократить правую часть команды s///. Кроме того, мы используем доллар внутри класса символов [...]
, который рассматривается как литерал.
sed -Ee "s/([\$]Date)([\$])/\1 $(date) \2/"
Или, возможно, мы можем сделать так, как показано:
sed -e '/\($Date\)\$/ '"s//\1 $(date) \$/"