O retorno do carro não deve ser um problema, read deve lê-lo bem. A nova linha (linefeed) é, pois é o delimitador padrão para read . Você pode usar o truque read -d '' para que funcione.
echo $'\r' | { IFS= read -r -n1 x; echo "$x"|xxd; } # CR
echo $'\n' | { IFS= read -r -n1 x; echo "$x"|xxd; } # LF fails
echo $'\n' | { IFS= read -d '' -r -n1 x; echo "$x"|xxd; } # LF ok
Mas, como dizem, você provavelmente não quer fazer coisas assim na shell. tr seria exatamente o que você precisa para excluir um conjunto fixo de caracteres, mas pelo menos o GNU tr funciona em bytes, não em caracteres, por isso não é muito útil para Unicode.
Acho que esse Perl deve funcionar, para dados UTF-8, se suas localidades estiverem definidas corretamente como UTF-8:
perl -C -pe 'tr/\x09\x0a\x0d\x20-\x{d7ff}\x{e000}-\x{fffd}\x{10000}-\x{10ffff}//cd' < in > out
Mas é melhor testar, não estou acostumado com as peculiaridades do Unicode.
tr/abc//cd exclui os caracteres que não estão listados em abc ( tr/// é, na verdade, destinado a transformar caracteres em outros, consulte perlop ). Ele recebe listas de caracteres, assim como intervalos, e \xHH significa o caractere com valor hexadecimal HH e \x{HHHH} um com valor HHHH . Portanto, o acima aceita 0x09 , 0x0a , 0x0d , tudo de 0x20 a 0xd7ff etc.
A lista acima é retirada diretamente da lista apresentada na pergunta. Vou deixar para o usuário final avaliar se ele deve ser alterado.