Desejo filtrar um arquivo por caractere (com o objetivo de remover caracteres xml inválidos dos quais não posso controlar a geração), mas não consigo copiar caracteres individuais de um arquivo para outro. Eu costumava printf
copiar seções literais, incluindo retornos de carro antes, mas agora ele não copia um retorno de carro como um, mas como uma string de comprimento vazio. Meu código:
infile=$1
outfile=$2
touch $outfile
while IFS= read -r -n1 char
do
# display one character at a time
printf "%s" "$char" >> $outfile
done < "$infile"
diff $infile $outfile
Não me importo de usar sed ou awk, mas teria que codificar os caracteres permitidos.
Char ::= #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF] /* any Unicode character, excluding the surrogate blocks, FFFE, and FFFF. */
O retorno do carro não deve ser um problema,
read
deve ser lido perfeitamente. A nova linha (linefeed) é, pois é o delimitador padrão pararead
. Você pode usar oread -d ''
truque para fazê-lo funcionar.Mas, como dizem, você provavelmente não quer fazer coisas assim no shell.
tr
seria exatamente o que você precisa para excluir um conjunto fixo de caracteres, mas pelo menos o GNUtr
funciona em bytes, não em caracteres, portanto, não é muito útil para Unicode.Acho que este Perl deve funcionar, para dados UTF-8, se suas localidades estiverem definidas corretamente como UTF-8:
Mas é melhor testar, não estou acostumado com as peculiaridades do Unicode.
tr/abc//cd
exclui os caracteres que não estão listados emabc
( natr///
verdade, serve para transformar caracteres em outros, consulteperlop
). Leva listas de caracteres, bem como intervalos, e significa o caractere com valor hexadecimal HH , e um com valor HHHH . Portanto, o acima aceita , , , tudo de a etc.\xHH
\x{HHHH}
0x09
0x0a
0x0d
0x20
0xd7ff
A lista acima é retirada diretamente da lista apresentada na pergunta. Vou deixar para o usuário final avaliar se deve ser alterado.