1

This is a followup of my previous question "Sed to print only first pattern match of the line"

The data I'm working on

... "one" ... "two" ... "three" ...

I wanted one to be printed and the answer I accepted was this

sed 's/[^"]*"\([^"]*\)".*/\1/'

I searched and tried to understand this regular expression but I couldn't wrap my head around this one.

What I understand is:

  • [^"] means do not match "
  • * means match 0 any number of characters preceded by *
  • \( and \) means store anything matching in between them to be referenced later by the corresponding number i.e in our case it is only \1
  • .* is greedy and means any number of characters

I don't understand what [^"]* here means.

How do I verbally read this whole regular expression so that I understand what's going on here

sed 's/[^"]*"\([^"]*\)".*/\1/'
2
NODE                     EXPLANATION
--------------------------------------------------------------------------------
  [^"]*                    any character except: '"' (0 or more times
                           (matching the most amount possible))
--------------------------------------------------------------------------------
  "                        '"'
--------------------------------------------------------------------------------
  \(                        group and capture to \1:
--------------------------------------------------------------------------------
    [^"]*                    any character except: '"' (0 or more
                             times (matching the most amount
                             possible))
--------------------------------------------------------------------------------
  \)                        end of \1
--------------------------------------------------------------------------------
  "                        '"'
--------------------------------------------------------------------------------
  .*                       any character except \n (0 or more times
                           (matching the most amount possible))

The second component of the sed command invokes \1 to use what was 'captured' in the parenthetical. It should be noted that the entire sed command is not itself a regular expression. In the construct s/needle/pin/g, the regular expression is needle or, if you like your regular expressions "wrapped" (e. g. for use in awk), /needle/.

  • 1
    @DopeGhoti Actually, the . also matches the newline, but a long as you go line by line, there is no newline to be matched. – Philippos Aug 3 '17 at 7:35
  • sed parses its input file line by line, so. – DopeGhoti Aug 3 '17 at 15:56
1

Since [^"]* means "any number of characters that is not a quote", and since sed regex are greedy, [^"]* ensures that the quote that follows is the first quote in the string. The second similar regex ensures that the quote that follows is the second one in the string. .* matches what follows that second quote.

Therefore [^"]*"\([^"]*\)".* means "match the whole line and put the second quote-delimited field in \1".

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.