Preciso substituir alguns caracteres não imprimíveis por espaços no arquivo.
Especificamente, todos os caracteres de 0x00
até 0x1F
, exceto 0x09
(TAB), 0x0A
(nova linha), 0x0D
(CR)
Até agora, eu só precisava substituir o 0x00
personagem. Como meu sistema operacional anterior era o AIX (sem comandos GNU), não posso usá-lo sed
(bem, posso, mas ele tem algumas limitações). Então, eu encontrei o próximo comando usando perl
, que funcionou como esperado:
perl -p -e 's/\x0/ /g' $FILE_IN > $FILE_OUT
Agora estou trabalhando no Linux, então esperava poder usar o sed
comando.
Minhas perguntas:
Este comando é apropriado para substituir esses caracteres? Eu tentei e parece funcionar, mas quero ter certeza:
perl -p -e 's/[\x00-\x08\x0B\x0C\x0E-\x1F]/ /g' $FILE_IN > $FILE_OUT
Eu pensei que
perl -p
funciona comosed
. Então, por que o comando anterior funciona (pelo menos, não falha) e o próximo não?sed -e 's/[\x00-\x08\x0B\x0C\x0E-\x1F]/ /g' $FILE_IN > $FILE_OUT
Isso me diz:
expressão sed: -e # 1, caractere 34: caractere de agrupamento inválido
perl -p
imprime o produto finalstdin
após realizar as operações desejadas, neste caso, é apenas uma substituição.sed
A expressão regular de Regex pode ser diferente deperl
.Respostas:
Esse é um trabalho típico para
tr
:No seu caso, não funciona
sed
porque você está em um local onde esses intervalos não fazem sentido. Se você quiser trabalhar com valores de byte em oposição a personagens e onde a ordem é baseado no valor numérico dos bytes, a sua melhor aposta é a de utilizar o idioma C . Seu código teria funcionado com oLC_ALL=C
GNUsed
, mas o usosed
(e muito menosperl
) é um pouco exagerado aqui (e eles\xXX
não são portáveis emsed
implementações enquanto essatr
abordagem é POSIX).Você também pode confiar na idéia do seu código de idioma sobre o que são os caracteres imprimíveis :
Mas com o GNU
tr
(como normalmente encontrado em sistemas baseados em Linux), isso funciona apenas em locais onde os caracteres são de byte único (normalmente, não UTF-8).No código de idioma C, isso também excluiria DEL (0x7f) e todos os valores de bytes acima (não no ASCII).
Nas localidades UTF-8, você pode usar o GNU
sed
que não tem o problema que o GNUtr
tem:(Note-se que aqueles
\r
,\t
não são padrão, e GNUsed
não irá reconhecê-los sePOSIXLY_CORRECT
está no ambiente (se tratá-los como barra invertida, r e t de ser parte do conjunto como POSIX requer)).Não converteria bytes que não formam caracteres válidos, se houver.
fonte
tr
comando faz. I compreender (mais ou menos) o queLC_ALL = C
é, mas não todos juntos. No entanto,tr -d
remove esses caracteres, mas quero substituir por espaços. Desculpe, o título estava errado. Acabei de perceber quando o @don_crissti foi modificado.XCOM
. Por exemplo, caracteres não ASCII comoÉ
são codificados (usandood -xa
) como0xC9
, então eu acho que seriaISO-8859-1
.locale -a
para ver se há códigos de idioma com iso8859-1 como o conjunto de caracteres em seu sistema e usarLC_CTYPE=<that-locale> tr ...[:print:]...
para converter não imprimíveis nesse código de idioma. Ou você pode usar o iconv para converter esses arquivos no conjunto de caracteres do código de idioma.LC_ALL=en_US.iso88591
. Portanto, seu command (tr -c '[:print:]\t\r\n' '[ *]'
) funciona perfeitamente sem modificar a localidade ou converter o arquivo. Muito obrigado.Eu estava tentando enviar uma notificação via libnotify, com conteúdo que pode conter caracteres não imprimíveis. As soluções existentes não funcionaram muito bem para mim (usando uma lista de desbloqueio de caracteres usando
tr
obras, mas retira qualquer caractere de vários bytes).Aqui está o que funcionou, ao passar no teste::
fonte