É possível usar o find
comando para encontrar todos os arquivos "não binários" em um diretório? Aqui está o problema que estou tentando resolver.
Eu recebi um arquivo de arquivos de um usuário do Windows. Este arquivo contém código fonte e arquivos de imagem. Nosso sistema de compilação não funciona bem com arquivos com finais de linha do Windows. Eu tenho um programa de linha de comando ( flip -u
) que irá inverter as terminações de linha entre * nix e windows. Então, eu gostaria de fazer algo assim
find . -type f | xargs flip -u
No entanto, se esse comando for executado em um arquivo de imagem ou em outro arquivo de mídia binário, ele corromperá o arquivo. Sei que poderia criar uma lista de extensões de arquivo e filtrar com isso, mas prefiro ter algo que não depende de mim para manter essa lista atualizada.
Então, existe uma maneira de encontrar todos os arquivos não binários em uma árvore de diretórios? Ou existe uma solução alternativa que devo considerar?
file
algum lugar utilidade em seu script / gasoduto para identificar se o arquivo é de dados ou textoRespostas:
Eu usaria
file
e canalizaria a saída no grep ou awk para encontrar arquivos de texto, depois extrairia apenas a parte do nome do arquivo dafile
saída e a canalizaria para o xargs.algo como:
Observe que o grep procura por 'texto ASCII' em vez de apenas um 'texto' - você provavelmente não quer mexer com documentos Rich Text ou arquivos de texto unicode etc.
Você também pode usar
find
(ou o que seja) para gerar uma lista de arquivos para examinarfile
:O
-d'\n'
argumento para xargs faz com que os xargs tratem cada linha de entrada como um argumento separado, atendendo a nomes de arquivos com espaços e outros caracteres problemáticos. isto é, uma alternativa paraxargs -0
quando a fonte de entrada não gera ou não pode gerar saída separada por NULL (comofind
a-print0
opção de). De acordo com o changelog, o xargs obteve a opção-d
/--delimiter
em setembro de 2005, portanto deve estar em qualquer distribuição Linux não antiga (não tinha certeza, e foi por isso que verifiquei - apenas me lembrei vagamente que era uma adição "recente").Observe que um feed de linha é um caractere válido nos nomes de arquivos, portanto, isso será interrompido se algum nome de arquivo tiver feeds de linha. Para usuários típicos do Unix, isso é patologicamente insano, mas não é inédito se os arquivos foram originados em máquinas Mac ou Windows.
Observe também que
file
não é perfeito. É muito bom em detectar o tipo de dados em um arquivo, mas ocasionalmente pode ficar confuso.Eu usei inúmeras variações deste método muitas vezes no passado com sucesso.
fonte
file
exibido emEnglish text
vez deASCII text
no meu sistema Solaris, então modifiquei essa parte de acordo. Além disso, substituíawk -F: '{print $1}'
pelo equivalentecut -f1 -d:
.grep -I
filtros bináriostext
deve ser suficiente. Isso também selecionaráfile
descrições comoASCII Java program text
ouHTML document text
outroff or preprocessor input text
.ASCII text
evitar bagunçar RTFs.Não. Não há nada de especial em um arquivo binário ou não binário. Você pode usar heurísticas como 'contém apenas caracteres em 0x01–0x7F', mas isso chamará arquivos de texto com arquivos binários de caracteres não ASCII e arquivos de texto de arquivos binários azarados.
Agora, depois de ignorar isso ...
arquivos zip
Se for proveniente do usuário do Windows como um arquivo zip, o formato zip suporta a marcação de arquivos como binários ou como texto no próprio arquivo morto. Você pode usar a
-a
opção de descompactar para prestar atenção e converter. Obviamente, veja no primeiro parágrafo o motivo pelo qual isso pode não ser uma boa ideia (o programa zip pode ter adivinhado errado ao criar o arquivo).O zipinfo informará quais arquivos são binários (b) ou texto (t) em sua listagem de arquivos zip.
outros arquivos
O comando file examinará um arquivo e tentará identificá-lo. Em particular, você provavelmente encontrará a opção
-i
(tipo MIME de saída) útil; converte apenas arquivos com o tipo texto / *fonte
Uma solução geral para processar apenas arquivos não binários
bash
usandofile -b --mime-encoding
:Entrei em contato com o autor do utilitário de arquivo e ele adicionou um
-00
parâmetro bacana na versão 5.26 (lançada em 16/04/2016, por exemplo, no atual Arch e Ubuntu 16.10), que imprimefile\0result\0
para vários arquivos alimentados a ele de uma só vez, desta maneira você pode fazer por exemplo:(A
awk
parte é filtrar todos os arquivos que não são binários.ORS
É o separador de saída.)Também pode ser usado em um loop, é claro:
Com base nisso e no anterior, criei um pequeno
bash
script para filtrar arquivos binários que utilizam o novo método usando o-00
parâmetro defile
nas versões mais recentes e voltando ao método anterior nas versões mais antigas:Ou aqui mais um POSIX-y, mas requer suporte para
sort -V
:fonte
A resposta aceita não encontrou todas elas para mim. Aqui está um exemplo usando grep's
-I
para ignorar binários e ignorando todos os arquivos ocultos ...Aqui está em uso em uma aplicação prática: dos2unix
https://unix.stackexchange.com/a/365679/112190
fonte
A resposta de Cas é boa, mas assume nomes de arquivos sãos ; em particular, assume-se que os nomes de arquivos não conterão novas linhas.
Não há uma boa razão para fazer essa suposição aqui, pois é bastante simples (e realmente mais limpo na minha opinião) lidar com esse caso corretamente:
O
find
comando utiliza apenas recursos especificados pelo POSIX . Usar-exec
para executar comandos arbitrários como testes booleanos é simples, robusto (manipula nomes de arquivos ímpares corretamente) e mais portáteis que-print0
.De fato, todas as partes do comando são especificadas pelo POSIX, exceto por
flip
.Observe que
file
não garante a precisão dos resultados retornados. No entanto, na prática, o grepping para "texto ASCII" em sua saída é bastante confiável.(Talvez ele perca alguns arquivos de texto, mas é muito improvável que identifique incorretamente um arquivo binário como "texto ASCII" e o altere - portanto, estamos errando por precaução.)
fonte
calls
pode ser bastante lento, por exemplo, para vídeos, ele mostra tudo sobre a codificação.-
.file
, pode levar vários arquivos como argumentos.find
comando irá anteceder./
a qualquer nome de arquivo passado para o comando shell; (3) Usargrep
como teste em uma únicafile
saída de comando por vez é a única maneira POSIX que eu posso ver para garantir o manuseio correto dos nomes de arquivos que podem conter novas linhas.file
suporta a--mime-encoding
flag e o--
separador, nenhum dos quais é garantido pelo POSIX .Ele encontrará todos os arquivos regulares (
-type f
) no diretório atual (ou abaixo) quegrep
consideram não-vazios e não-binários.Ele usa
grep -I
para distinguir entre arquivos binários e não binários. O-I
sinalizador e fará comgrep
que saia com um status de saída diferente de zero quando detectar que um arquivo é binário. Um arquivo "binário" é, de acordo comgrep
, um arquivo que contém caracteres fora do intervalo ASCII imprimível.A
-q
opção paragrep
fará com que ele saia com um status de saída zero se o padrão fornecido for encontrado, sem emitir nenhum dado. O padrão que usamos é um único ponto, que corresponderá a qualquer caractere.Se o arquivo for não-binário e se contiver pelo menos um caractere, o nome do arquivo será impresso.
Se você se sente corajoso, também pode conectar-se a
flip -u
ele:fonte
Tente o seguinte:
Onde o argumento de
grep '[^ -~]'
é'[^<tab><space>-~]'
.Se você digitar em uma linha de comando do shell, digite Ctrl+ Vantes Tab. Em um editor, não deve haver problema.
'[^<tab><space>-~]'
corresponderá a qualquer caractere que não seja texto ASCII (os retornos de carro são ignorados porgrep
).-L
imprimirá apenas o nome do arquivo dos arquivos que não correspondem-Z
produzirá nomes de arquivos separados por um caractere nulo (paraxargs -0
)fonte
grep -P
(se disponível)\t
está disponível. Como alternativa, usando a tradução de código de idioma se o shell oferecer suporte:$'\t'
(bash
ezsh
faça).Solução alternativa:
O comando dos2unix converterá as terminações de linha do Windows CRLF em Unix LF e ignorará automaticamente os arquivos binários. Aplico-o recursivamente usando:
fonte
dos2unix
pode levar vários nomes de arquivos como argumento, é muito mais eficiente para fazerfind . -type f -exec dos2unix {} +
sudo find / (-type f -and -path '* / git / *' -iname 'README') -exec grep -liI '100644 \ | 100755' {} \; -exec flip -u {} \;
i. (-type f -and -path '* / git / *' -iname 'README'): pesquisa arquivos em um caminho que contém o nome git e o arquivo com o nome README. Se você conhece alguma pasta e nome de arquivo específicos para pesquisar, será útil.
O comando ii.-exec executa um comando no nome do arquivo gerado por find
iii. \; indica final do comando
iv. {} é a saída do arquivo / nome da pasta encontrado na pesquisa anterior
v.Múltiplos comandos podem ser executados posteriormente. Anexando -exec "command" \; como com -exec flip -u \;
vii.grep
você pode clonar este diretório de teste e testá-lo: https://github.com/alphaCTzo7G/stackexchange/tree/master/linux/findSolution204092017
resposta mais detalhada aqui: https://github.com/alphaCTzo7G/stackexchange/blob/master/linux/findSolution204092017/README.md
fonte