Os utilitários padrão do Unix gostam grep
e diff
usam alguma heurística para classificar os arquivos como "texto" ou "binário". (Por exemplo grep
, a saída pode incluir linhas como Binary file frobozz matches
.)
Existe um teste conveniente que se possa aplicar em um zsh
script para executar uma classificação "texto / binário" semelhante? (Diferente de algo parecido grep '' somefile | grep -q Binary
.)
(Eu percebo que qualquer teste desse tipo seria necessariamente heurístico e, portanto, imperfeito.)
file
é um utilitário padrão e pode executar a mágica de arquivos para determinar os tipos de arquivos da melhor maneira possível. Ele sabe a maioria dos formatos de texto e faz um trabalho bastante decente em formatos binários. Se tudo que você está tentando fazer é descobrir se um arquivo é de texto ou não, isso é o comando que você está interessado.file
serão impressas, por exemploshell script
, para alguns arquivos que eu gostaria de classificar como "texto". Existe uma maneirafile
de imprimir apenastext
oubinary
?cut
comandos.file
saída da tubulaçãocut
é a solução - com certeza, há um espaço em falta que faz com que ela falhe e a maioria das pessoas aborda o Y em vez do X, mas os comentários e respostas de Stéphane mostram a maneira correta de determinar se o arquivo é texto ou não.Respostas:
Se você pedir
file
apenas o tipo MIME, obterá muitos tipos diferentestext/x-shellscript
,application/x-executable
etc., mas imagino que se você apenas verificar a parte "texto", deverá obter bons resultados. Por exemplo (-b
para nenhum nome de arquivo na saída):fonte
file
, que você pode perder alguns formatos de texto:application/xml
(e semelhante, como RSS),application/ecmascript
,application/json
,image/svg+xml
, ... Você teria que whitelist aqueles.application/*
tipos não são destinados ao consumo humano, mesmo quando podem ser baseados em texto para facilitar o desenvolvimento e a depuração. É por isso que existe umtext/xml
e umapplication/xml
. Portanto, a questão de considerá-los como texto depende das necessidades do OP.cut -d/ -f1
Outra abordagem seria usar
isutf8
a coleção moreutils .Ele sai com 0 se o arquivo for UTF-8 ou ASCII válido, ou curto-circuito, imprime uma mensagem de erro (silencie com
-q
) e sai com 1 caso contrário.fonte
Se você gosta da heurística usada pelo GNU
grep
, você pode usá-lo:Ele procura por NUL bytes no primeiro buffer lido do arquivo (alguns quilo-bytes para um arquivo normal, mas pode ser muito menor para um pipe ou soquete ou alguns dispositivos como
/dev/random
). Nos códigos de idioma UTF-8, também sinaliza sequências de bytes que não formam caracteres UTF-8 válidos. Ele assume queLC_ALL
não está definido para algo em que o idioma não é o inglês.O
${1-$REPLY}
formulário permite usá-lo como umzsh
qualificador glob:listaria os arquivos binários .
fonte
Você pode tentar determinar se
iconv
pode ler o arquivo. Isso tem menos desempenho do quefile
(que lê apenas alguns bytes desde o início), mas oferece resultados mais confiáveis:Isso torna
iconv
basicamente um no-op, mas se encontrar dados inválidos (UTF-8 inválido neste exemplo), ele vomitará e sairá.fonte
-f
e em-t
vez das opções longas do GNU o tornaria mais portátil. Observe que ele chamará "binário" dos arquivos que não pode abrir. Ele chamará os arquivos vazios de "texto".iconv
. Mas-f
e-t
geralmente são melhores.Você pode escrever um script que chama
file
e usar uma declaração de caso para verificar os casos nos quais está interessado.Por exemplo
embora, é claro, possa haver muitos casos especiais de interesse. Apenas checando
strings
uma cópialibmagic
, vejo cerca de 200 casos, por exemplo,Alguns usam a string "text" como parte de um tipo diferente, por exemplo,
da mesma forma
script
poderia ser parte de uma palavra, mas não vejo problemas neste caso. Mas um script deve verificar"text"
como uma palavra , não como uma substring .Como lembrete, a
file
saída não usa uma descrição precisa que sempre teria "script" ou "texto". Casos especiais são algo a considerar. Um acompanhamento comentou que os--mime-type
trabalhos, embora essa abordagem não funcionasse, para.svg
arquivos. No entanto, em um teste, vejo estes resultados para arquivos svg:que eu selecionei depois de ver milhares de arquivos mostrar apenas 6 com "texto" na saída do tipo MIME. Indiscutivelmente, combinar o "xml" no final da saída do tipo MIME poderia ser mais útil, digamos, do que combinar o "SVG", mas usar um script para fazer isso leva você de volta à sugestão feita aqui.
A saída de
file
requer algum ajuste em qualquer cenário e não é 100% confiável (é confundida por vários dos meus scripts Perl, chamando-os de "dados").Existe mais de uma implementação de
file
. O mais usado faz seu trabalholibmagic
, que pode ser usado em diferentes programas (talvez não diretamentezsh
, emborapython
possa).De acordo com a tabela de comparação de teste de arquivo para shell, Perl, Ruby e Python , o Perl tem um
-T
opção que pode ser usada para fornecer essas informações. Mas ele não lista nenhum recurso comparável parazsh
.Leitura adicional:
fonte
file
, a saída do GNU para arquivos svg:SVG Scalable Vector Graphics image
não contém a palavra texto. Eu pensei que essa abordagem seria melhor do que a resposta aceita para verificar o tipo MIME, mas ainda falta alguns tipos.image/svg+xml
. Na verdade - apenas verifiquei um arquivo de 1000 iguais, apenas 6 apareceram como "texto" de acordo apenas com o tipo MIME. Vou ficar com um script, que pelo menos pode ser feito para funcionar conforme necessário.file
tem uma opção--mime-encoding
que tenta detectar a codificação de um arquivo.Você pode usar
file --mime-encoding | grep binary
para detectar se um arquivo é um arquivo binário. Funciona de maneira confiável, embora possa ser confundido por um único caractere inválido em um arquivo de texto longo.Por exemplo, alias
cat
ao seguinte script de shell para evitar arruinar meu terminal abrindo inadvertidamente um arquivo binário:fonte
As categorias são arbitrárias. Antes de responder como fazer uma classificação, você precisa de uma definição (estrita). Para ter uma definição, você precisa de um objetivo .
Então, o que você quer fazer com essa classificação?
fonte
vai fazer isso. Consulte a documentação para
-B
e-T
(pesquise nessa página a sequênciaThe -T and -B switches work as follows
).fonte
perl -le 'print -B $ARGV[0] ? "binary" : "text"' --
pode ser mais claro. Ou aindaperl -le 'print -B $_ ? "binary" : "text", @ARGV > 1 ? "\t$_" : "" for @ARGV' --
Eu contribuí com https://github.com/audreyr/binaryornot Ele ainda não possui um wrapper de linha de comando, mas esta é uma biblioteca Python simples, fácil de chamar, mesmo a partir da CLI. Ele usa uma heurística bastante eficiente para determinar se um arquivo é texto ou binário.
fonte
Agora, essa resposta é um pouco antiga, mas acho que meu amigo me ensinou um ótimo "truque" para fazer isso.
Você usa o
diff
comando e verifica seu arquivo em um arquivo de texto de teste:$ diff filetocheck testfile.txt
Agora, se
filetocheck
for um arquivo binário, a saída seria:Binary files filetocheck and testfile.txt differ
Dessa forma, você pode aproveitar o
diff
comando e, por exemplo, escrever uma função que faz a verificação em um script.fonte