Como imprimir caracteres literais de / para arquivo no bash?

1

Eu quero filtrar um arquivo por caractere (com o propósito de remover caracteres xml inválidos que não posso controlar a geração de), mas não consigo nem mesmo copiar caracteres individuais de um arquivo para outro. Eu usei printf para copiar seções literais, incluindo retornos de carro antes, mas agora ele não copia um retorno de carro como um, mas como uma cadeia 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

Eu não me importo de usar sed ou awk, mas eu 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. */

    
por Timothy Swan 01.02.2018 / 21:20

1 resposta

2

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.

    
por 01.02.2018 / 22:30