Como encontrar arquivos com 100% de caracteres NUL em seu conteúdo?

13

Qual é o comando da linha de comando do Linux que pode identificar esses arquivos?

AFAIK O comando find (ou grep ) só pode corresponder a uma string específica dentro do arquivo de texto. Mas quero corresponder todo o conteúdo, ou seja, quero ver quais arquivos correspondem à expressão regular find . cat | grep+ , ignorando os caracteres de fim de linha . Talvez o idioma %code% possa funcionar, mas não sei como fazer o grep ignorar linhas (e tratar o arquivo como binário).

Antecedentes: A cada poucos dias, quando meu laptop congela, minha partição btrfs perde informações: arquivos abertos para gravação obtêm seu conteúdo substituído por zeros (o tamanho do arquivo permanece mais ou menos intacto). Eu uso a sincronização e não quero que esses arquivos falsos se propaguem: preciso de uma maneira de identificá-los para poder pegá-los a partir do backup.

    
por Adam Ryczkowski 20.12.2012 / 11:52

6 respostas

10

Você pode usar grep para ␀ caracteres usando o modo regex Perl:

$ echo -ne "
for path in *.foo
do
    grep -P "[^
$ echo -ne "
for path in *.foo
do
    grep -P "[^%pre%]" "$path" || echo "$path"
done
%pre%" > nul.bin $ echo -ne "%pre%x%pre%" > non-nul.bin $ grep -P "[^%pre%]" *.bin Binary file non-nul.bin matches
]" "$path" || echo "$path" done
%pre%" > nul.bin $ echo -ne "%pre%x%pre%" > non-nul.bin $ grep -P "[^%pre%]" *.bin Binary file non-nul.bin matches

Então você pode usar isto:

%pre%     
por 20.12.2012 / 13:43
5

Concordo com o que D_Bye diz sobre encontrar a raiz do problema.

De qualquer forma, para verificar se um arquivo contém apenas \n e / ou tr , você pode usar %code% :

<file tr -d '
<file tr -d '%pre%\n' | wc -c
\n' | wc -c

Que retorna 0 para arquivos nulos / nova linha e vazios.

    
por 20.12.2012 / 12:48
4

Aqui está um pequeno programa em Python que pode fazer isso:

import sys
def chunkCheck(fileObject, chunkSize=1024):
    while True:
        data = fileObject.read(chunkSize)
        if not data:
            return False
        if data.strip("
$ printf '
files=( file1 file2 )
for file in "${files[@]}"; do
    ./onlynulls "$file" || printf '%s\n' "$file"
done
import sys
def chunkCheck(fileObject, chunkSize=1024):
    while True:
        data = fileObject.read(chunkSize)
        if not data:
            return False
        if data.strip("
$ printf '
files=( file1 file2 )
for file in "${files[@]}"; do
    ./onlynulls "$file" || printf '%s\n' "$file"
done
%pre%%pre%' > file $ ./onlynulls file && echo "Only nulls" || echo "Non-null characters" Only nulls $ printf a >> file $ ./onlynulls file && echo "Only nulls" || echo "Non-null characters" Non-null characters
"): return True sys.exit(chunkCheck(open(sys.argv[1])))
%pre%' > file $ ./onlynulls file && echo "Only nulls" || echo "Non-null characters" Only nulls $ printf a >> file $ ./onlynulls file && echo "Only nulls" || echo "Non-null characters" Non-null characters
"): return True sys.exit(chunkCheck(open(sys.argv[1])))

E em ação:

%pre%

Você pode verificar vários arquivos usando -exec , xargs , GNU parallel e programas semelhantes do find. Alternativamente, isso irá imprimir nomes de arquivos que precisam ser tratados:

%pre%

Tenha em mente que, se você for passar a saída deste para outro programa, os nomes de arquivos podem conter novas linhas, então você deve delimitá-lo de forma diferente (apropriadamente, com %code% ).

Se você tiver muitos arquivos, seria melhor usar uma opção para processamento paralelo, já que isso só lê um arquivo de cada vez.

    
por 20.12.2012 / 12:14
4

Eu suspeito que esses arquivos são esparsos, ou seja, eles não têm nenhum espaço em disco alocado para eles, eles apenas especificam um tamanho de arquivo ( du reportaria 0 para eles).

Nesse caso, com o GNU find, você poderia fazer (assumindo que nenhum caminho de arquivo contenha caracteres de nova linha):

find . -type f -size +0 -printf '%b:%p\n' | grep '^0:' | cut -d: -f2-
    
por 20.12.2012 / 18:58
2

Localizar arquivos que contenham apenas caracteres nulos '\ 0' e caracteres de nova linha '\ n'.
O q em sed faz com que cada pesquisa de arquivo seja encerrada imediatamente ao localizar qualquer caractere não nulo em uma linha.

find -type f -name 'file-*' |
  while IFS= read -r file ;do 
      out=$(sed -n '1=; /^\x00\+$/d; i non-null
                      ; q' "$file")
      [[ $out == "1" ]] &&  echo "$file"
  done

Faça arquivos de teste

> file-empty
printf '%s\n' 'line1' 'line2' 'line3'      > file-with-text           
printf '%4s\n' '' '' xx | sed 's/ /\x00/g' > file-with-text-and-nulls
printf '%4s\n' '' '' '' | sed 's/ /\x00/g' > file-with-nulls-and-newlines
printf '%4s'   '' '' '' | sed 's/ /\x00/g' > file-with-nulls-only

saída

./file-with-nulls-and-newlines
./file-with-nulls-only
    
por 20.12.2012 / 12:39
0

Python

Arquivo único

Defina o alias:

alias is_binary="python -c 'import sys; sys.exit(not b\"\x00\" in open(sys.argv[1], \"rb\").read())'"

Teste:

$ is_binary /etc/hosts; echo $?
1
$ is_binary 'which which'; echo $?
0

Vários arquivos

Encontre todos os arquivos binários recursivamente:

IS_BINARY='import sys; sys.exit(not b"\x00" in open(sys.argv[1], "rb").read())'
find . -type f -exec bash -c "python -c '$IS_BINARY' {} && echo {}" \;

Para localizar todos os arquivos não binários, altere && com || .

    
por 01.06.2015 / 23:15