Identificando e removendo caracteres nulos no UNIX

98

Eu tenho um arquivo de texto contendo caracteres nulos indesejados (ASCII NUL, \0). Quando tento visualizá-lo vi, vejo ^@símbolos intercalados em texto normal. Como posso:

  1. Identificar quais linhas no arquivo contêm caracteres nulos? Tentei usar o grep para \0e \x0, mas não funcionou.

  2. Remover os caracteres nulos? Executando stringsno arquivo limpei, mas eu só estou me perguntando se esta é a melhor maneira?

dogbane
fonte
1
Esse tipo de pergunta provavelmente pertence ao SuperUser.com
Olivier Lalonde,
2
Na verdade, esta pergunta está em superuser.com: superuser.com/questions/75130/how-to-remove-ths-symbol-with-vim
jrb

Respostas:

130

Eu usaria tr:

tr < file-with-nulls -d '\000' > file-without-nulls

Se você está se perguntando se o redirecionamento de entrada no meio dos argumentos do comando funciona, ele funciona. A maioria das conchas irá reconhecer e lidar com I / O redirecionamento ( <, >...) em qualquer lugar na linha de comando, na verdade.

Pontudo
fonte
e um "arquivo diff com nulos arquivo sem nulos" deve mostrar quais linhas têm caracteres nulos? Isso traz de volta muito mais do que o esperado.
dogbane
10
Na verdade, eu acredito que deveria ser, tr -d '\000' < file-with-nulls > file-without-nullsjá que <faz parte da funcionalidade do shell pipe e não tr.
Mikael S
9
A maioria dos shells irá reconhecer e lidar com <ou> em qualquer lugar na string do argumento, na verdade. Me surpreendeu também.
pra
1
+1 Para uso de redirecionamento de entrada em vez de cat |. Uma solução boa e limpa que resolveu meu problema.
Krzysztof Jabłoński
4
@Pointy '\ 000' é usado no lugar de '\ 0' na especificação de grupo aberto POSIX para tr. Essa é uma boa razão para preferir
Harold Fischer
67

Use o seguinte comando sed para remover os caracteres nulos em um arquivo.

sed -i 's/\x0//g' null.txt

esta solução edita o arquivo no local, importante se o arquivo ainda estiver sendo usado. passando -i'ext 'cria um backup do arquivo original com o sufixo' ext 'adicionado.

rekha_sri
fonte
6
Nota: No FreeBSD (e acredito que também no Mac OS X), sed -i requer uma extensão no próximo argumento, mas pode estar vazia. Nesses sistemas, adicione um '', como em: sed -i '' 's/\x0//g "$FILE".
Tim Čas 01 de
1
Esta é uma ordem de magnitude mais rápida do que trpara mim
diachedélico
Para mim, usando Git para Windows e $ sed --version-> sed (GNU sed) 4.7, tive que usar a seguinte invocação para obter um arquivo de backup chamado example.csv.bak:sed -i.bak 's/\x0//g' example.csv
Andrew Keeton
1
@ Tim. Como você fez muito bem, faltou apenas um 'então deveria ser sed -i' '' s / \ x0 // g 'algum_arquivo.xml
Darko
@Darko Então eu fiz. Opa.
Tim Čas
22

Um grande número de caracteres NUL indesejados, digamos um a cada dois bytes, indica que o arquivo está codificado em UTF-16 e que você deve usar iconvpara convertê-lo em UTF-8.

Ignacio Vazquez-Abrams
fonte
1
Eu fiquei sem espaço em disco enquanto meu aplicativo estava registrando. Isso resultou nesses personagens.
dogbane,
Por exemplo, ele funciona usando este comando: iconv -f UTF-16 -t UTF-8 file.
djule5
7

Eu descobri o seguinte, que imprime quais linhas, se houver, têm caracteres nulos:

perl -ne '/\000/ and print;' file-with-nulls

Além disso, um despejo octal pode informar se há nulos:

od file-with-nulls | grep ' 000'
dogbane
fonte
5

Se as linhas do arquivo terminarem com \ r \ n \ 000, o que funciona é excluir \ n \ 000 e substituir \ r por \ n.

tr -d '\n\000' <infile | tr '\r' '\n' >outfile
wwmbes
fonte
PS. Se você estiver em um shell DOS do Windows, poderá obter as versões GNU / win32 dos comandos Unix no Sourceforge.net. Eu os uso o tempo todo. Verifique "od" o comando octal dump para analisar o que está em um arquivo ...
wwmbes
2

Aqui está um exemplo de como remover caracteres NULL usando ex(no local):

ex -s +"%s/\%x00//g" -cwq nulls.txt

e para vários arquivos:

ex -s +'bufdo!%s/\%x00//g' -cxa *.txt

Para recursividade, você pode usar a opção globbing **/*.txt (se for suportada pelo seu shell).

Útil para scripts, pois sed e seu -iparâmetro é uma extensão BSD não padrão.

Veja também: Como verificar se o arquivo é binário e ler todos os arquivos que não são?

Kenorb
fonte
1

Eu usei:

recode UTF-16..UTF-8 <filename>

para se livrar dos zeros no arquivo.

logisec
fonte
0

Eu enfrentei o mesmo erro com:

import codecs as cd
f=cd.open(filePath,'r','ISO-8859-1')

Resolvi o problema mudando a codificação para utf-16

f=cd.open(filePath,'r','utf-16')
Ming Young
fonte