Shell – Why sed prints first string from file even if it’s failed to find matching groups

regular expressionsedshell

I'm trying to write sed expression which will extract matching groups from file.

E.g. I have .cue sheet and I want to extract it's genre tag. It has following format:

$ cat file.cue | grep GENRE
REM GENRE "POP"

I've created sed expression to extract this tag and replace quotes around it:

$  sed -e 's/REM[ \t]*GENRE[ \t]*\(.*\)/\1/;s/"\(.*\)"/\1/;q' file.cue 
POP

My question is why if it's failed to find matching group it will just print first string?

$  sed -e 's/REMerror[ \t]*GENRE[ \t]*\(.*\)/\1/;s/"\(.*\)"/\1/;q' file.cue 
REM GENRE POP

Example of cue-sheet:

REM GENRE "POP"
REM DATE 2012
REM DISCID EC10BD10
REM COMMENT "ExactAudioCopy v0.99pb5"
PERFORMER "JAM Project"
TITLE "JAM Project BEST COLLECTION IX THE MONSTERS"
FILE "LACA-15250.flac" WAVE
  TRACK 01 AUDIO
    TITLE "THE MONSTERS"
    PERFORMER "JAM Project"
    INDEX 01 00:00:00

Best Answer

Your sed script, as it stands, will always print the first line regardless of whether it was modified. The default action for sed is to print its pattern space (current input line1) to standard out after it's done applying all your other commands.

So, basically, what you're telling it to do is to apply a few substitutions and then quit. What this means is that it will try your substitutions on the first line and print it after the substitutions (regardless of whether they were successful) since this is the default action. It then encounters q and quits processing altogether.

If you want to suppress the default printing action, you need the -n switch, but then you need to explicitly instruct sed to print the lines where substitution was successful:

sed -n 's/REM[ \t]*GENRE[ \t]*"\(.*\)"/\1/p;q' your_file_here

Now this script will print the first line where the substitution was successful and then quit.

Note that you didn't need two substitutions, only one is enough.

Unrelated side note

No need for

cat your_file | grep 'foobar'

when

grep 'foobar' your_file

would do.


1Not always the current input line: you may for example add lines to the pattern space.

Related Question