I have a bash script that extracts headers from the MIME Source of an email. The idea is that I only want to capture the headers of the message nothing else. It's not quite working right though.

I want it to do the following:

1) Start at the top of the email.
2) Isolate just the part that starts with "From" (my particular upstream mail server ALWAYS starts the header with a line containing this).
3) Capture all lines below it UNTIL the first line break.
4) Don't bother capture stuff from the remainder of the email.

I thought I could do it with this sed pattern: sed -n "/From/,/^$/p"

Unfortunately it triggers on other instances of "From". For example, if someone forwardes a message and there is content like:

---------- Forwarded message ----------
From: Newsletter <newsletter@foo.com>
Date: Wed, Jan 28, 2015 at 9:16 PM
Subject: Blargenflugent
To: examplerecipient@domain.com

How can I have sed ignore content after the first line break?

sed '/From/,$!d;/./!q' <infile

...the above expression instructs sed to delete from output all lines which do !not fall within the range of /From/ through the $last line. Each time it deletes a line it stops reading its script and starts over with the next input line from the top - and so it doesn't read the next command.

So the /./!quit command means sed only quits input on the first line following the first occurrence of From in its input which does !not contain at least a single .character.

  • I like this approach but the single quotes concern me a little. Is there anyway to protect against malicious headers going into sed? For example, if a header had rm -fr / in it, how would sed handle it with the single quotes? I thought double-quotes were preferred. – Mike B Feb 8 '15 at 3:17
  • 1
    @MikeB - sed doesn't care at all about quotes - excepting the backslash, I guess. But even backslashes are for its script - not its input. You can print any amount of single quotes and/or rm commands at sed's stdin and it wouldn't do anything but perform the text alteration commands as you instruct it to do in its script. The single quotes are for the shell in which you call sed - they instruct the shell not to try anything funny on the contents of that argument and to pass it along literally to the exec'd sed process. – mikeserv Feb 8 '15 at 3:24
  • Sooo, single quotes = good/safe. Thanks That explains why things aren't working quite right when I try sed "/From/,$!d;/./!q" – Mike B Feb 8 '15 at 3:27
  • 2
    @MikeB - ah, yes. Shell expansions are interpreted within "double-quotes" and $! is a special shell parameter representing the pid of the last backgrounded process in the shell's process group. So it's either expanding that to nothing at all which would happen if you haven't backgrounded a process since opening the shell and which should result in sed not executing at all and quitting with error at invocation, or it's expanding to some number which could make sed behave the same or miss the match depending on whether the number is high enough to include it or not. – mikeserv Feb 8 '15 at 3:36
sed -n '/From/!p;/From/{s/From/foo/;p;: rest; n; p; b rest;}' file

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.