Home > Back-end >  Sed: specific exact two match
Sed: specific exact two match

Time:03-29

I have this line in a file. The blanks between the words can be tabs or spaces

#define FN_AUTO_FN_FNSECTOR   Function(2)     /* FN_ comment*/

and I wanted output to be like this :

2:"FN_AUTO_FN_FNSECTOR",

I have this code:

echo -e "#define \t \t\t FN_AUTO_FN_FNSECTOR \t\t\t  Function(2)\t     /* FN_ comment*/" |sed "s/.*\(\([[:blank:]]\)FN_*[_a-zA-Z]*\).[^ ].*(\([^\)]*\)).*/\3:\"\1\",/"

But the output is with preceding blanks between quote and FN_AUTO_FN_FNSECTOR :

2:"     FN_AUTO_FN_FNSECTOR",

How can I avoid it? Solution has to be robust spaces or tabs must not affect the selection. My solution has to be in sed, Preferably in one single command.

SOLUTION: Thanks to Aaron. The solution I preferred is this

echo -e "#define \t\t\r FN_AUTO_FN_FNSECTOR \t\r\t\t  Function(2)\t     /* FN_ comment*/" |sed "s/.*\s\(FN_*[_a-zA-Z]*\).[^ ].*(\([^\)]*\)).*/\2:\"\1\",/"

CodePudding user response:

In your sed command, the first capturing group (which starts with your fist opening \( contains the [[:blank:]] class which matches the spaces that precede FN_AUTO_FN_FNSECTOR.

I suggest using the following command :

sed -E 's/.*\s(FN_*[_a-zA-Z]*).*\(([^)])\).*/\2:\"\1"/'

Tested here.

In this command I use -E to switch to extended regular expressions where (...) denotes capturing groups while \(...\) denotes literal brackets. It also enables me (on modern GNU sed at least) to use \s to represent blanks.

CodePudding user response:

Using sed

$ sed 's/[^[:space:]]*[[:space:]]\([^[:space:]]*\)[^(]*(\(.\).*/\2:"\1",/' input_file
2:"FN_AUTO_FN_FNSECTOR",

CodePudding user response:

You can use

sed -E 's/.*[[:blank:]](FN[^[:blank:]]*)[[:blank:]] [^[:blank:]] \(([^()])\).*/\2:"\1",/'

If you have a GNU sed, you can replace [[:blank:]] with \s (any whitespace) and [^[:blank:]] with \S (any non-whitespace):

sed -E 's/.*\s(FN\S*)\s \S \(([^()]*)\).*/\2:"\1",/'

See the online demo:

#!/bin/bash
s='#define FN_AUTO_FN_FNSECTOR   Function(2)     /* FN_ comment*/'
sed -E 's/.*[[:blank:]](FN[^[:blank:]]*)[[:blank:]] [^[:blank:]] \(([^()]*)\).*/\2:"\1",/' <<< "$s"
## => 2:"FN_AUTO_FN_FNSECTOR",

Note that -E option allows POSIX ERE syntax where unescaped is a one or more quantifier, and to define capturing groups you need unescaped pairs of parentheses.

Pattern details:

  • .* - any text
  • [[:blank:]] - a horizontal whitespace char
  • (FN[^[:blank:]]*) - Group 1: FN and zero or more non-whitespace chars
  • [[:blank:]] - one or more horizontal whitespace chars
  • [^[:blank:]]
  • \( - a literal ( char (in POSIX BRE, it should not be escaped, but in ERE, it must)
  • ([^()]*) - Group 2: any zero or more chars other than ( and ) (note that ( and ) inside bracket expressions do not need escaping in any POSIX (and all non-POSIX that I know of) regex flavor)
  • \) - a literal ) in POSIX ERE
  • .* - any text
  • Related