Дві важливі підводні камені
які досі були проігноровані іншими відповідями:
- Вилучення нового рядка від розширення команди
- Видалення символу 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
рішення, і я не знаю жодного корисного рішення для цього.
Приклад:
printf "a\0b" | od -tx1
S="$(printf "a\0b")"
printf "$S" | od -tx1
Виходи:
0000000 61 00 62
0000003
0000000 61 62
0000002
Га, наш НУЛ пішов!
Обхідні шляхи:
Кодування 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.
cat
або$(<someFile)
призведе до неповного виходу (розмір менше , ніж реальний файл).