Две важные ловушки
, которые до сих пор игнорировались другими ответами:
- Удаление завершающего перевода строки из расширения команды
- Удаление символов NUL
Завершение удаления новой строки из расширения команды
Это проблема для:
value="$(cat config.txt)"
Решения типа
, но не для решений на основе read
.
Расширение команды удаляет завершающие символы новой строки:
S="$(printf "a\n")"
printf "$S" | od -tx1
Выходы:
0000000 61
0000001
Это нарушает наивный метод чтения из файлов:
FILE="$(mktemp)"
printf "a\n\n" > "$FILE"
S="$(<"$FILE")"
printf "$S" | od -tx1
rm "$FILE"
Обходной путь POSIX: добавьте дополнительный символ в расширение команды и удалите его позже:
S="$(cat $FILE; printf a)"
S="${S%a}"
printf "$S" | od -tx1
Выходы:
0000000 61 0a 0a
0000003
Практически POSIX обходной путь: ASCII-кодирование. Смотри ниже.
Удаление символов NUL
Не существует нормального способа Bash для хранения NUL-символов в переменных .
Это влияет как на расширение, так и на read
решения, и я не знаю хорошего обходного пути для этого.
Пример: * +1051 *
printf "a\0b" | od -tx1
S="$(printf "a\0b")"
printf "$S" | od -tx1
Выходы:
0000000 61 00 62
0000003
0000000 61 62
0000002
Ха, наш NUL ушел!
Обходные:
Кодировка ASCII. См. Ниже.
использовать расширение bash $""
литералы:
S=$"a\0b"
printf "$S" | od -tx1
Работает только для литералов, поэтому не полезно для чтения из файлов.
Обходной путь для ловушек
Сохраните версию файла в кодировке uuencode base64 в переменной и декодируйте перед каждым использованием:
FILE="$(mktemp)"
printf "a\0\n" > "$FILE"
S="$(uuencode -m "$FILE" /dev/stdout)"
uudecode -o /dev/stdout <(printf "$S") | od -tx1
rm "$FILE"
Выход:
0000000 61 00 0a
0000003
uuencode и udecode POSIX 7 , но не в Ubuntu 12.04 по умолчанию (пакет sharutils
) ... Я не вижу альтернативы POSIX 7 для расширения процесса bash <()
, за исключением расширения запись в другой файл ...
Конечно, это медленно и неудобно, поэтому я думаю, что реальный ответ таков: не используйте Bash, если входной файл может содержать символы NUL.