È necessario rimuovere i caratteri degli spazi bianchi dal $IFSparametro per readinterrompere il salto di quelli iniziali e finali (con -n1, il carattere degli spazi bianchi, se presente, sarebbe sia iniziale che finale, quindi ignorato):
while IFS= read -rn1 a; do printf %s "$a"; done
Ma anche allora bash readsalterà i personaggi newline, con i quali puoi aggirare:
while IFS= read -rn1 a; do printf %s "${a:-$'\n'}"; done
Sebbene tu possa usare IFS= read -d '' -rn1invece o anche meglio IFS= read -N1(aggiunto in 4.1, copiato da ksh93(aggiunto in o)) quale è il comando per leggere un carattere.
Nota che bash readnon può far fronte ai personaggi NUL. E ksh93 ha gli stessi problemi di bash.
Con zsh:
while read -ku0 a; do print -rn -- "$a"; done
(zsh può far fronte ai caratteri NUL).
Si noti che quelli read -k/n/Nleggono un numero di caratteri , non byte . Pertanto, per i caratteri multibyte, potrebbe essere necessario leggere più byte fino a quando non viene letto un carattere completo. Se l'input contiene caratteri non validi, si può finire con una variabile che contiene una sequenza di byte che non forma caratteri validi e che la shell potrebbe finire per contare come più caratteri . Ad esempio in una locale UTF-8:
$ printf '\375\200\200\200\200ABC' | bash -c '
IFS= read -rN1 a; echo "${#a}"'
6
Ciò \375introdurrebbe un carattere UTF-8 a 6 byte. Tuttavia, il sesto ( A) sopra non è valido per un carattere UTF-8. Si finisce ancora con \375\200\200\200\200Ain $a, che bashconta come 6 caratteri sebbene i primi 5 non siano realmente personaggi, solo 5 byte che non fanno parte di alcun personaggio.
IFSnulla per far sì che gli spazi bianchi sopravvivano alla divisione delle parole.