Você precisa remover os caracteres de espaço em branco do $IFS
parâmetro para read
parar de ignorar caracteres iniciais e finais (com -n1
, o caractere de espaço em branco, se houver algum, seria inicial e final, portanto, ignorado):
while IFS= read -rn1 a; do printf %s "$a"; done
Mas, mesmo assim, o bash read
ignora os caracteres de nova linha, com os quais você pode contornar:
while IFS= read -rn1 a; do printf %s "${a:-$'\n'}"; done
Embora você possa usar em IFS= read -d '' -rn1
vez disso ou até melhor IFS= read -N1
(adicionado em 4.1, copiado de ksh93
(adicionado o
))) que é o comando para ler um caractere.
Observe que o bash read
não pode lidar com caracteres NUL. E o ksh93 tem os mesmos problemas que o bash.
Com zsh:
while read -ku0 a; do print -rn -- "$a"; done
(zsh pode lidar com caracteres NUL).
Observe que aqueles read -k/n/N
leem vários caracteres , não bytes . Portanto, para caracteres multibyte, eles podem precisar ler vários bytes até que um caractere completo seja lido. Se a entrada contiver caracteres inválidos, você poderá acabar com uma variável que contém uma sequência de bytes que não forma caracteres válidos e que o shell pode acabar contando como vários caracteres . Por exemplo, em um código de idioma UTF-8:
$ printf '\375\200\200\200\200ABC' | bash -c '
IFS= read -rN1 a; echo "${#a}"'
6
Isso \375
introduziria um caractere UTF-8 de 6 bytes. No entanto, o sexto ( A
) acima é inválido para um caractere UTF-8. Você ainda termina com \375\200\200\200\200A
in $a
, que bash
conta como 6 caracteres, embora os 5 primeiros não sejam realmente caracteres, apenas 5 bytes não fazem parte de nenhum caractere.
IFS
como nada para que os espaços em branco sobrevivam à divisão de palavras.