Reputation: 1194
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
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
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
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/
'
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
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 resultss{pattern}{replacement}
is similar to sed's s///
but more powerfule
modifier interprets the replacement as code\K
forgets anything matched so far, so the cflags part matches, but isn't replacedr
modifier returns the result of a substitution instead of changing the variable in placeUpvotes: 1