3

I have an input stream containing strings representing file types. I want to print all file types that are not text or are PostScript (PostScript is a text file type). I tried the following sed expression:

sed -n '/PostScript/pb; /text/!p'

However, this returns an error:

sed: -e expression #1, char 14: extra characters after command

This is confusing to me because I thought it was acceptable to specify multiple commands (e.g. bp) after a pattern.

I can get the behavior I want using the following expression:

sed -n '/PostScript/p; /PostScript/b; /text/!p'

How can I get the behavior I want without duplicating the /PostScript/ pattern in my expression?

| improve this question | | | | |
3

The common way to get a group of commands executed together (e.g., subject to a condition like a pattern match) is to group them with curly braces.
With GNU sed:

sed -n '/PostScript/{p; b}; /text/!p'

Without grouping and with any sed branch to end of script in both cases and delete the other lines:

sed -e '/PostScript/b' -e '/text/!b' -e 'd'

Also, for the record:

I thought it was acceptable to specify multiple commands (e.g. bp) after a pattern.

Editing commands for an address (what you call pattern is a context address) are one thing and the substitution flags g,p,w and no. are another thing.

The syntax for the latter is

s/pattern/replacement/[flags]

in other words flags can be combined (e.g. gp or 7w outfile) while the syntax for the former is

[2addr] {editing command
editing command
...
}

in other words commands must be separated by newlines (in some cases they can be separated by semicolons).

| improve this answer | | | | |
  • thanks, after seeing your answer and then reading through the sed documentation again, this is now obvious! can't believe I didn't think of it before :P – jayhendren May 18 '15 at 19:09
3

POSIXly:

$ sed -n '/PostScript/p; //b
/text/!p'

POSIX define that if regular expression is empty, sed shall behave as if the last RE used in the last command applied.


With your command, you need ; between p and b to make it work with GNU sed:

$ sed -n '/PostScript/p; //b; /text/!p'

With POSIX sed, you can't use //b; because ; is a valid branch name. You need to use newline as terminator between command.

| improve this answer | | | | |
  • sed -n '/PostScript/p;b; /text/!p' doesn't work for me with GNU sed version 4.1.5. This expression only prints lines that contain the pattern PostScript (presumably because it unconditionally branches to the end of the expression after running /PostScript/p). – jayhendren May 18 '15 at 18:53
  • thanks, the quick edits made it a bit tricky to write accurate comments :) in any case sed -n '/PostScript/p; //b; /text/!p' is what has been working for me. – jayhendren May 18 '15 at 18:59
  • @jayhendren: And it only works with GNU sed. ; was considered a valid branch name in POSIX sed. – cuonglm May 18 '15 at 19:01

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.