Como grep todos os arquivos xml que não começam com “”

2

Como posso encontrar todos os arquivos xml no diretório atual e em todos os subdiretórios, que não iniciam com < na primeira linha.

Eu tentei isso, mas o grep não funciona:

find . -type f -name '*.xml' | grep "^[^<]" | head -n 1
    
por Bizboss 22.07.2015 / 09:35

5 respostas

3

Para aplicar a primeira linha de cada arquivo e imprimir se eles corresponderem, você pode usar xargs e awk

find . -type f -name "*.xml" -print0 | xargs -0 -I{} awk 'NR==1&&!/^</' {}

Para imprimir o nome do arquivo dos arquivos

find . -type f -name "*.xml" -print0 | xargs -0 -I{} awk 'NR==1&&!/^</{print FILENAME}' {}
    
por 22.07.2015 / 10:57
4

Você já tem algumas respostas sólidas, mas eu ofereço uma alternativa - a especificação XML é bastante rigorosa, e arquivos que não começam com < não são realmente XML .

Portanto, uma abordagem simples pode ser simplesmente testar se o arquivo é 'válido' ou não. Todos os analisadores XML podem fazer isso, mas aqui está um exemplo:

#!/usr/bin/perl
use strict;
use warnings; 
use XML::Twig;

foreach my $filename ( @ARGV ) { 
    eval { XML::Twig -> new -> parsefile ( $filename ); };
    print "File: $filename is not valid XML $@\n" if $@;
}

Isso pode preencher o formulário como:

perl -MXML::Twig -e 'foreach ( @ARGV ) { eval { XML::Twig -> new -> parsefile ( $_ ) }; print "File: $filename is not valid XML $@\n" if $@;' *.xml

Se a travessia recursiva for importante, então File::Find também ajudará:

#!/usr/bin/env perl
use strict;
use warnings;
use XML::Twig;
use File::Find;

sub check_valid_xml {
    #skip any files that don't end in '.xml'
    next unless m/\.xml$/;   
    #validate this file
    eval { XML::Twig->new->parsefile($File::Find::name); };
    #report errors if detected - parser will abort on invalid XML
    if ($@) { print "File $File::Find::name is not valid XML $@"; }
}

find( \&check_valid_xml, "." );

Isso detectará qualquer 'XML incorreto', que incluirá os arquivos que você especificou na sua pergunta.

    
por 22.07.2015 / 13:27
3

Se o seu awk suportar a instrução nextfile (a maioria faz):

 find . -name '*.xml' -type f \( -size 0 -print -o -exec awk '
   !/^</ {print FILENAME}; {nextfile}' {} + \)
    
por 22.07.2015 / 14:06
1
find .//. -name \*.xml -type f -exec head -n1 {} + |
sed -ne:n -e'\|^==> \.//\.|!{H;$!d' -e\} \
    -ex   -e'\|\.xml <==\n|!{G;x;d' -e\} \
          -e's|[^/]*//\(.*\) <==\n[^<]*$||p'

head lista nomes de arquivos por conta própria. Assim, você pode apenas -exec e ter sed para ver sua entrada para o relatório de head nos nomes dos arquivos que não correspondem a < em sua primeira linha.

Se você quiser apenas evitar listar nomes de arquivo para arquivos cujo primeiro caractere é < , isso é feito com facilidade. De fato, com um GNU grep pode ser mais fácil ...

find .//. -name \*.xml -type f -exec grep -EHaom1 '^.?' {} +|
sed     -ne'\|^\.//\.|!{H;$!d' -e\} \
         -e'x;\|\.xml:|!{G;x;d' -e\} \
         -e's|:[^<]*$||p;$!d;x;s|||p'

Não devemos testar diretamente o < char com grep porque podemos acabar testando a terceira ou quarta linha se o primeiro começar com < , mas o que podemos fazer é dizer grep para parar em 1 -m atch para -o nly 0 ou 1 char na cabeça de uma linha. Isso significa que grep imprimirá nossos nomes de arquivos como ...

.//./path/to/xml.xml:.

E assim, tudo o que o sed deve fazer é garantir que ele reúne o inteiro nome do arquivo (caso ele contenha caracteres de nova linha) e testar se o último caractere no string é < se não for, sed retira os dois últimos caracteres e imprime os resultados.

    
por 22.07.2015 / 11:29
0

Festa pura:

shopt -s globstar
for i in **/*.c;do
    read -N 1 h < "$i";
    if [[ $h != "<" ]]; then
        # echo "found $i";
        # do stuff with "$i"
    fi;
done

read -N 1 lê um único caractere do arquivo, sem precisar bifurcar / executar nada. Se você precisar apenas de uma lista de nomes de arquivos, use outra coisa que facilite o uso do estilo -print0 .

    
por 22.07.2015 / 14:56

Tags