Parsing filename do email bruto

2

Precisa obter um nome de arquivo de lista delimitado por vírgulas em um email. Aqui estão alguns exemplos de entrada com 1 tendo muitos caracteres especiais:

Content-Disposition: attachment;
        filename="How-To_21_Monitor_Mode_Deployment_Guide.pdf"; size=3886046;
        creation-date="Fri, 27 Oct 2017 16:23:20 GMT";
        modification-date="Fri, 27 Oct 2017 16:24:30 GMT"

Content-Disposition: attachment; filename="How-To_24_Low_Impact_Mode.pdf";
        size=6714113; creation-date="Fri, 27 Oct 2017 16:23:20 GMT";
        modification-date="Fri, 27 Oct 2017 16:24:31 GMT"

Content-Disposition: attachment;
        filename="SBTGxYVWPE1wI9SAjl5b2PUfF1LCjbU3aChsoch5eXuI4GrIP9bRhfiaOuwL1U
 ;.,~!@#$%....txt"; size=3966; creation-date="Fri, 27 Oct 2017 16:23:20 GMT";
        modification-date="Fri, 27 Oct 2017 16:23:20 GMT"

Isso funciona, mas preocupado se foi mais de 3 linhas e não é eficiente:

grep --no-group-separator --line-buffered -A 2 '^Content-Disposition: ' | sed -e '/\;$/!{N;s/\n//}' -n -e 's/.*filename\=//p' | sed -e 's/ size\=.*//' | sed 's/\;$//' | sed ':a;N;$!ba;s/\n/,/g'

Tentamos trabalhar com uma única linha sed:

sed -n '/^Content-Disposition: /,/\"\; size\=/{/\;$/!{x;N;s/\n//g}};s/.*filename\=//p;s/ size\=.*//;s/\;$//;:a;N;$!ba;s/\n/,/g;

Seria apreciado por um único comando, de preferência com sed.

    
por Roy Walker 31.10.2017 / 16:46

3 respostas

0

to get a comma delimited list filenames in an email

Solução

GNU awk :

awk -v RS='\n\n' 'BEGIN{ fn="" }
       match($0, /filename="([^"]+)";[[:space:]]+size=/, a){ 
           gsub(/[[:space:]]*/, "", a[1]); 
           fn = (fn!=""? fn", ":"")a[1] 
       }END{ print fn }' file
  • fn - a string resultante contendo todos os nomes de arquivos (após o processamento)

  • -v RS='\n\n' - define o separador de registro como quebra de linha dupla

  • /filename="([^"]+)";[[:space:]]+size=/ - padrão regex para capturar o nome do arquivo em cada cabeçalho Content-Disposition na matriz de correspondências a

A saída:

How-To_21_Monitor_Mode_Deployment_Guide.pdf, How-To_24_Low_Impact_Mode.pdf, SBTGxYVWPE1wI9SAjl5b2PUfF1LCjbU3aChsoch5eXuI4GrIP9bRhfiaOuwL1U;.,~!@#$%....txt
    
por 31.10.2017 / 17:50
2

Satō Katsura está certo. Aqui está um script Perl rápido, supondo que você tenha a mensagem completa em um arquivo.

cpan install Email::MIME File::Slurp::Tiny
perl -MEmail::MIME -MFile::Slurp::Tiny=read_file -wE '
    my $email = Email::MIME->new( read_file(shift @ARGV) );
    my $count = 0;
    $email->walk_parts(sub {
        my $part = shift;
        my %header = $part->header_str_pairs;
        if (exists $header{"Content-Disposition"}) {
            my ($filename) = $header{"Content-Disposition"} =~ m/(?<=filename=")([^"]+)/;
            say ++$count .":". $filename;
        }
    })
' email.eml
    
por 31.10.2017 / 17:30
0

RomanPerekhrest conseguiu 99%, obrigado! Esta é a última linha que eu usei, apenas tive que fazer um pequeno ajuste para manipular espaços em nomes de arquivos e incluir as aspas ao redor das strings. Awk definitivamente melhor que sed nesse caso.

awk -v RS = '\ n \ n' 'BEGIN {fn=""} corresponde ($ 0, / nome do arquivo = ("[^"] + "); [[espaço:]] + tamanho = / , a) {gsub (/ \ n /, "", a [1]); fn = (fn!=""? fn ",": "") a [1]} FIM {print fn} '

    
por 31.10.2017 / 20:39