Bạn cần xóa các ký tự khoảng trắng khỏi $IFS
tham số read
để dừng bỏ qua các ký tự đầu và cuối (với -n1
ký tự khoảng trắng nếu có cả hai đầu và cuối, do đó bỏ qua):
while IFS= read -rn1 a; do printf %s "$a"; done
Nhưng ngay cả sau đó bash read
sẽ bỏ qua các ký tự dòng mới, mà bạn có thể làm việc với:
while IFS= read -rn1 a; do printf %s "${a:-$'\n'}"; done
Mặc dù bạn có thể sử dụng IFS= read -d '' -rn1
thay thế hoặc thậm chí tốt hơn IFS= read -N1
(được thêm vào 4.1, được sao chép từ ksh93
(thêm vào o
)) là lệnh để đọc một ký tự.
Lưu ý rằng bash's read
không thể đối phó với các ký tự NUL. Và ksh93 có vấn đề tương tự như bash.
Với zsh:
while read -ku0 a; do print -rn -- "$a"; done
(zsh có thể đối phó với các ký tự NUL).
Lưu ý rằng những người read -k/n/N
đọc một số ký tự , không phải byte . Vì vậy, đối với các ký tự đa nhân, họ có thể phải đọc nhiều byte cho đến khi một ký tự đầy đủ được đọc. Nếu đầu vào chứa các ký tự không hợp lệ, bạn có thể kết thúc bằng một biến chứa chuỗi byte không tạo thành các ký tự hợp lệ và lớp vỏ có thể sẽ được tính là nhiều ký tự . Ví dụ: trong miền địa phương UTF-8:
$ printf '\375\200\200\200\200ABC' | bash -c '
IFS= read -rN1 a; echo "${#a}"'
6
Điều đó \375
sẽ giới thiệu một ký tự UTF-8 6 byte. Tuy nhiên, cái thứ 6 ( A
) ở trên không hợp lệ cho ký tự UTF-8. Bạn vẫn kết thúc với \375\200\200\200\200A
in $a
, được bash
tính là 6 ký tự mặc dù 5 ký tự đầu tiên không thực sự là ký tự, chỉ có 5 byte không tạo thành một phần của bất kỳ ký tự nào.
IFS
thành không có gì để có khoảng trắng tồn tại trong quá trình phân tách từ.