2

Need to get a comma delimited list filenames in an email. Here is some input examples with 1 having lots of special characters:

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"

This works, but concerned if it went more than 3 lines and it is not efficient:

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'

Tried to get it working with a single sed line:

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

Would be appreciated for a single command preferably with sed.

1
  • 3
    This is naive. The filename can be encoded, and can be split over several lines. You won't reconstruct it with sed. You probably won't reconstruct it with awk, either. You need a full MIME parser to deal with all cases. Oct 31, 2017 at 15:53

3 Answers 3

2

Satō Katsura is right. Here's a quick Perl script, assuming you have the full email message in a file.

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
0

to get a comma delimited list filenames in an email

GNU awk solution:

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 - the resulting string containing all the filenames(after processing)

  • -v RS='\n\n' - set record separator as double linebreak

  • /filename="([^"]+)";[[:space:]]+size=/ - regex pattern to capture the filename in each Content-Disposition header into array of matches a


The output:

How-To_21_Monitor_Mode_Deployment_Guide.pdf, How-To_24_Low_Impact_Mode.pdf, SBTGxYVWPE1wI9SAjl5b2PUfF1LCjbU3aChsoch5eXuI4GrIP9bRhfiaOuwL1U;.,~!@#$%....txt
0

RomanPerekhrest got it 99%, thanks! This is the final line I used, just had to make a minor tweak to handle spaces in filenames and include the quotes around strings. Awk definitely better than sed in this case.

awk -v RS='\n\n' 'BEGIN{ fn="" } match($0, /filename=("[^"]+");[[:space:]]+size=/, a){gsub(/\n/, "", a[1]);fn = (fn!=""? fn",":"")a[1]}END{ print fn }'

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.