'Sed: specific exact two match
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\",/"
Solution 1:[1]
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.
Solution 2:[2]
Using sed
$ sed 's/[^[:space:]]*[[:space:]]\([^[:space:]]*\)[^(]*(\(.\).*/\2:"\1",/' input_file
2:"FN_AUTO_FN_FNSECTOR",
Solution 3:[3]
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
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 | HatLess |
Solution 3 | Wiktor Stribiżew |