Hai cạm bẫy quan trọng
mà đã bị bỏ qua bởi các câu trả lời khác cho đến nay:
- Trailing loại bỏ dòng mới từ mở rộng lệnh
- Xóa ký tự NUL
Trailing loại bỏ dòng mới từ mở rộng lệnh
Đây là một vấn đề cho:
value="$(cat config.txt)"
loại giải pháp, nhưng không cho read
các giải pháp dựa trên.
Mở rộng lệnh loại bỏ các dòng mới:
S="$(printf "a\n")"
printf "$S" | od -tx1
Đầu ra:
0000000 61
0000001
Điều này phá vỡ phương pháp đọc ngây thơ từ các tập tin:
FILE="$(mktemp)"
printf "a\n\n" > "$FILE"
S="$(<"$FILE")"
printf "$S" | od -tx1
rm "$FILE"
Giải pháp thay thế POSIX: nối thêm char vào phần mở rộng lệnh và xóa nó sau:
S="$(cat $FILE; printf a)"
S="${S%a}"
printf "$S" | od -tx1
Đầu ra:
0000000 61 0a 0a
0000003
Hầu như cách giải quyết POSIX: mã hóa ASCII. Xem bên dưới.
Xóa ký tự NUL
Không có cách Bash lành mạnh để lưu trữ các ký tự NUL trong các biến .
Điều này ảnh hưởng đến cả mở rộng và read
giải pháp và tôi không biết cách giải quyết tốt nào cho nó.
Thí dụ:
printf "a\0b" | od -tx1
S="$(printf "a\0b")"
printf "$S" | od -tx1
Đầu ra:
0000000 61 00 62
0000003
0000000 61 62
0000002
Ha, NUL của chúng ta đã biến mất!
Cách giải quyết:
Mã hóa ASCII. Xem bên dưới.
sử dụng bash mở rộng bằng $""
chữ:
S=$"a\0b"
printf "$S" | od -tx1
Chỉ hoạt động cho chữ, vì vậy không hữu ích để đọc từ các tập tin.
Cách giải quyết cho những cạm bẫy
Lưu trữ một phiên bản mã hóa uuencode base64 của biến trong biến và giải mã trước mỗi lần sử dụng:
FILE="$(mktemp)"
printf "a\0\n" > "$FILE"
S="$(uuencode -m "$FILE" /dev/stdout)"
uudecode -o /dev/stdout <(printf "$S") | od -tx1
rm "$FILE"
Đầu ra:
0000000 61 00 0a
0000003
uuencode và udecode là POSIX 7 nhưng không có trong Ubuntu 12.04 theo mặc định ( sharutils
gói) ... Tôi không thấy một thay thế POSIX 7 cho <()
phần mở rộng thay thế quy trình bash trừ việc ghi vào tệp khác ...
Tất nhiên, điều này chậm và bất tiện, vì vậy tôi đoán câu trả lời thực sự là: không sử dụng Bash nếu tệp đầu vào có thể chứa các ký tự NUL.
cat
hoặc$(<someFile)
sẽ dẫn đến một đầu ra không đầy đủ (kích thước nhỏ hơn tệp thực).