Vous devez supprimer les caractères d'espacement du $IFSparamètre pour readarrêter de sauter les caractères de début et de fin (avec -n1, le caractère d'espacement s'il y en a serait à la fois de début et de fin, donc ignoré):
while IFS= read -rn1 a; do printf %s "$a"; done
Mais même dans ce cas, bash readignorera les caractères de nouvelle ligne, avec lesquels vous pouvez contourner:
while IFS= read -rn1 a; do printf %s "${a:-$'\n'}"; done
Bien que vous puissiez utiliser à la IFS= read -d '' -rn1place ou même mieux IFS= read -N1(ajouté en 4.1, copié depuis ksh93(ajouté en o)) qui est la commande pour lire un caractère.
Notez que bash ne readpeut pas gérer les caractères NUL. Et ksh93 a les mêmes problèmes que bash.
Avec zsh:
while read -ku0 a; do print -rn -- "$a"; done
(zsh peut gérer les caractères NUL).
Notez que ceux-ci read -k/n/Nlisent un certain nombre de caractères , pas d' octets . Ainsi, pour les caractères multi-octets, ils peuvent avoir à lire plusieurs octets jusqu'à ce qu'un caractère complet soit lu. Si l'entrée contient des caractères non valides, vous pouvez vous retrouver avec une variable qui contient une séquence d'octets qui ne forme pas de caractères valides et que le shell peut finir par compter comme plusieurs caractères . Par exemple, dans un environnement local UTF-8:
$ printf '\375\200\200\200\200ABC' | bash -c '
IFS= read -rN1 a; echo "${#a}"'
6
Cela \375introduirait un caractère UTF-8 de 6 octets. Cependant, le 6ème ( A) ci-dessus n'est pas valide pour un caractère UTF-8. Vous vous retrouvez toujours avec \375\200\200\200\200Ain $a, qui bashcompte pour 6 caractères bien que les 5 premiers ne soient pas vraiment des caractères, seulement 5 octets ne faisant partie d'aucun caractère.
IFSà rien pour que les espaces blancs survivent à la séparation des mots.