Debe eliminar los caracteres de espacio en blanco del $IFS
parámetro para read
dejar de omitir los caracteres iniciales y finales (con -n1
el carácter de espacio en blanco si alguno sería tanto inicial como final, por lo que se omite):
while IFS= read -rn1 a; do printf %s "$a"; done
Pero incluso entonces, bash read
omitirá los caracteres de nueva línea, con los que puede trabajar:
while IFS= read -rn1 a; do printf %s "${a:-$'\n'}"; done
Aunque podría usar IFS= read -d '' -rn1
en su lugar o incluso mejor IFS= read -N1
(agregado en 4.1, copiado de ksh93
(agregado o
)), que es el comando para leer un carácter.
Tenga en cuenta que bash read
no puede hacer frente a los caracteres NUL. Y ksh93 tiene los mismos problemas que bash.
Con zsh:
while read -ku0 a; do print -rn -- "$a"; done
(zsh puede hacer frente a caracteres NUL).
Tenga en cuenta que esos read -k/n/N
leen una cantidad de caracteres , no bytes . Entonces, para los caracteres multibyte, pueden tener que leer varios bytes hasta que se lea un carácter completo. Si la entrada contiene caracteres no válidos, puede terminar con una variable que contiene una secuencia de bytes que no forma caracteres válidos y que el shell puede contar como varios caracteres . Por ejemplo, en un entorno local UTF-8:
$ printf '\375\200\200\200\200ABC' | bash -c '
IFS= read -rN1 a; echo "${#a}"'
6
Eso \375
introduciría un carácter UTF-8 de 6 bytes. Sin embargo, el sexto ( A
) anterior no es válido para un carácter UTF-8. Todavía terminas con \375\200\200\200\200A
in $a
, que bash
cuenta como 6 caracteres, aunque los primeros 5 no son realmente caracteres, solo 5 bytes no forman parte de ningún carácter.
IFS
en nada para que los espacios en blanco sobrevivan a la división de palabras.