Почему $'\ 0' или $'\ x0' - пустая строка? Должен быть нулевой символ, не так ли?

позволяет расширение $'string', Мой man bash говорит:

Слова формы $'string' рассматриваются специально. Слово расширяется до string, при этом символы с обратным слэшем-экранированием заменяются в соответствии со стандартом ANSI C. Последующие последовательности обратного слэша, если они есть, декодируются следующим образом:
          \a предупреждение (звонок)
          \b backspace
          \e
          \e escape-символ
          \f feed feed           \n новая строка
          \r возврат каретки
          \t горизонтальная вкладка
          \v вертикальная вкладка
          \ обратная косая черта
          \' одинарная цитата
          \" двойная цитата
          \nnn восьмибитовый символ, значением которого является восьмеричное значение nnn (от одной до трех цифр)
          \xHH восьмибитовый символ, значение которого представляет собой шестнадцатеричное значение HH (одна или две шестнадцатеричные цифры)
          \cx символ управления x

Расширенный результат одинарный, как будто знак доллара не присутствовал.

Но почему bash не преобразовать $'\0' и $'\x0' в нулевой символ?
Документировано? Есть ли причина? (Является ли это функцией или ограничением или даже ошибкой?)

$ hexdump -c <<< _$'\0'$'\x1\x2\x3\x4_'
0000000   _ 001 002 003 004   _  \n
0000007

echo дает ожидаемый результат:

> hexdump -c < <( echo -e '_\x0\x1\x2\x3_' )
0000000   _  \0 001 002 003   _  \n
0000007

Моя версия bash

$ bash --version | head -n 1
GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu)

Почему echo $'foo\0bar' не ведет себя как echo -e 'foo\0bar'?

Ответы

Ответ 1

Это ограничение. bash не позволяет строковым значениям содержать внутренние байты NUL.

Символьные строки Posix (и C) не могут содержать внутренние NUL. См., Например, определение Posix символьной строки (выделено мной):

3.92 Строка символов

Смежная последовательность символов , заканчивающаяся и включающая первый нулевой байт.

Аналогично, стандарт C достаточно явным образом указывает на символ NUL в символьных строках:

& sect; 5.2.1p2 & hellip; байт со всеми битами, установленными в 0, называемый нулевым символом, должен существовать в базовом наборе символов выполнения; он используется для завершения символьной строки.

Posix явно запрещает использование NUL (и /) в именах файлов (XBD 3.170) или в переменных среды (XBD 8.1 "... считается, что заканчивается нулевым байтом."

В этом контексте языки команд оболочки, включая bash, имеют тенденцию использовать одно и то же определение символьной строки, как последовательность символов, отличных от NUL, заканчивающихся одним NUL.

Вы можете свободно передавать NUL через каналы bash, и ничто не мешает вам назначать переменную оболочки на выход программы, которая выводит байт NUL. Однако последствия "неуказаны" в соответствии с Posix (XSH 2.6.3 "Если вывод содержит нулевые байты, поведение не указано".). В bash NUL удаляются, если вы не вставляете NUL в строку, используя синтаксис bash C-escape ($'\0'), и в этом случае NUL закончит завершение значения.

В практической заметке рассмотрим разницу между двумя следующими способами попыток вставить NUL в stdin утилиты:

$ # Prefer printf to echo -n
$ printf $'foo\0bar' | wc -c
3
$ printf 'foo\0bar' | wc -c
7
$ # Bash extension which is better for strings which might contain %
$ printf %b 'foo\0bar' | wc -c
7

Ответ 2

Но почему bash не конвертировать $'\0' и $'\x0' в нулевой символ?

Поскольку нулевой символ завершает строку.

$ echo $'hey\0you'
hey

Ответ 3

Это нулевой символ, но он зависит от того, что вы подразумеваете под этим.

Нулевой символ представляет собой пустую строку, которую вы получаете при ее расширении. Это особый случай, и я думаю, что это подразумевается документацией, но фактически не заявлено.

В C двоичный ноль '\0' завершает строку и сама по себе также представляет пустую строку. Bash записывается в C, поэтому, вероятно, это следует из этого.

Изменить: POSIX упоминает пустую строку в нескольких местах. В "Базовых определениях" он определяет пустую строку как:

3.146 Пустая строка (или нулевая строка)
Строка, первый байт которой является нулевым байтом.