Vinay Verma
Vinay Verma

Reputation: 1194

Remove characters between two patterns using sed

I have below use case where I need to remove some special characters (",/,\) using sed.

sample.txt

srcs : [a.c] cflags : [abcd@ef]
srcs : ["b.c"] cflags : [ab\cd"ef]
srcs : [r/.c] cflags : [a""bcd*ef""]
srcs : [g.c] cflags : [ab/cd*ef]

Need to remove (\,",/) from only cflags entry in each line. Expected output :

srcs : [a.c] cflags : [abcd@ef]
srcs : ["b.c"] cflags : [abcdef]
srcs : [r/.c] cflags : [abcd*ef]
srcs : [g.c] cflags : [abcd*ef]

Tried sed substitution mechanism with regex which searches string between "cflags" and "]" which returns strings between cflags and ] :

cat sample.txt | sed 's/cflags : \(.*\)]/\1/'

srcs : [a.c] [abcd@ef
srcs : ["b.c"] [ab\cd"ef
srcs : [r/.c] [a""bcd*ef""
srcs : [g.c] [ab/cd*ef

Substituted with '' but it removes entire cflags entry :

cat sample | sed 's/cflags : \(.*\)]/''/'

srcs : [a.c]
srcs : ["b.c"]
srcs : [r/.c]
srcs : [g.c]

Looking for a regex which can find (\,",/) between cflags and ']' in every line and then it can be just deleted using sed.

Upvotes: 1

Views: 392

Answers (4)

potong
potong

Reputation: 58420

This might work for you (GNU sed):

sed -E ':a;s/(.*cflags.*)["\\/]/\1/;ta' file

Keep everything upto and including cflags on a line and remove any \,/ or " characters thereafter.

If it must only amend the line between the second pair of square brackets, use:

sed -E ':a;s/(.*cflags[^[]*\[[^]]*)[\\/"]/\1/;ta' file

Upvotes: 2

RavinderSingh13
RavinderSingh13

Reputation: 133518

Could you please try following, if you are ok with awk here:

awk '
match($0,/cflags[^]]*\]/){
  val=substr($0,RSTART,RLENGTH)
  gsub(/\\|,|"|\//,"",val)
  print substr($0,1,RSTART-1) val substr($0,RSTART+RLENGTH)
  val=""
}
'  Input_file

Explanation of above code:

awk '                                                          ##Starting awk program from here.
match($0,/cflags[^]]*\]/){                                     ##Using match to match regex from cflags till ] here.
  val=substr($0,RSTART,RLENGTH)                                ##Creating variable val which is sub-string of RSTART and RLENGTH values.
  gsub(/\\|,|"|\//,"",val)                                     ##Globally substituting \,"/ with NULL in variable val here.
  print substr($0,1,RSTART-1) val substr($0,RSTART+RLENGTH)    ##Printing before part, actual part and last part of lines here,in this program.
  val=""                                                       ##Nullifying variable val here.
}
'  Input_file                                                  ##Mentioning Input_file name here.

Output will be as follows.

srcs : [a.c] cflags : [abcd@ef]
srcs : ["b.c"] cflags : [abcdef]
srcs : [r/.c] cflags : [abcd*ef]
srcs : [g.c] cflags : [abcd*ef]

Upvotes: 1

KamilCuk
KamilCuk

Reputation: 141020

You can't, like, apply the regex to only a part of the string in sed. So the method to do it, is to hold the line in hold space. Then extract the part of string you need to apply the regex. Then apply the regex - ie. remove the " / \ characters. Then take the line from hold space and re-shuffle it, so to replace the part of the string you wanted to replace with the replaced part (och, I hope this makes sense).

The following script:

cat <<'EOF' |
srcs : [a.c] cflags : [abcd@ef]
srcs : ["b.c"] cflags : [ab\cd"ef]
srcs : [r/.c] cflags : [a""bcd*ef""]
srcs : [g.c] cflags : [ab/cd*ef]
EOF
sed '
    # hold the line
    h
    # remove everything before clags
    s/.*cflags : //
    # replace the " \ / for nothing, ie. remove them
    # alternatively s/\("\|\\\|\/\)//g or s@\("\|\\\|/\)@@g 
    # but I think the following is more readable
    s/"//g
    s/\\//g
    s/\///g
    # append the holded line
    G
    # shuffle the pattern space for the output
    s/\(.*\)\n\(.*\)cflags : .*/\2cflags : \1/
'

outputs on repl:

srcs : [a.c] cflags : [abcd@ef]
srcs : ["b.c"] cflags : [abcdef]
srcs : [r/.c] cflags : [abcd*ef]
srcs : [g.c] cflags : [abcd*ef]

And a oneliner:

sed 'h;s/.*cflags : //;s/"//g;s/\\//g;s/\///g;G;s/\(.*\)\n\(.*\)cflags : .*/\2cflags : \1/'

Upvotes: 0

choroba
choroba

Reputation: 241868

Not easy in sed, but possible in Perl:

perl -pe '
    s{cflags : \[\K([^]]*\])}{
        $1 =~ s,[\\/"],,gr
    }e' -- sample.txt
  • -p reads the input line by line and prints the results
  • s{pattern}{replacement} is similar to sed's s/// but more powerful
  • the e modifier interprets the replacement as code
  • \K forgets anything matched so far, so the cflags part matches, but isn't replaced
  • the r modifier returns the result of a substitution instead of changing the variable in place

Upvotes: 1

Related Questions