how to regex replace before colon?

Viewed 196

this is my original string:

NetworkManager/system connections/Wired 1.nmconnection:14 address1=10.1.10.71/24,10.1.10.1

I want to only add back slash to all the spaces before ':'

so, this is what I finally want:

NetworkManager/system\ connections/Wired\ 1.nmconnection:14 address1=10.1.10.71/24,10.1.10.1

I need to do this in bash, so, sed, awk, grep are all ok for me.

I have tried following sed, but none of them work

echo NetworkManager/system connections/Wired 1.nmconnection:14 address1=10.1.10.71/24,10.1.10.1 | sed 's/ .*\(:.*$\)/\\ .*\1/g'
echo NetworkManager/system connections/Wired 1.nmconnection:14 address1=10.1.10.71/24,10.1.10.1 | sed 's/\( \).*\(:.*$\)/\\ \1.*\2/g'
echo NetworkManager/system connections/Wired 1.nmconnection:14 address1=10.1.10.71/24,10.1.10.1 | sed 's/ .*\(:.*$\)/\\ \1/g'
echo NetworkManager/system connections/Wired 1.nmconnection:14 address1=10.1.10.71/24,10.1.10.1 | sed 's/\( \).*\(:.*$\)/\\ \1\2/g'

thanks for answering my question. I am still quite newbie to stackoverflow, I don't know how to control the format in comment. so, I just edit my original question

my real story is:

when I do grep or use cscope to search keyword, for example "address1" under /etc folder. the result would be like:

./NetworkManager/system connections/Wired 1.nmconnection:14 address1=10.1.10.71/24,10.1.10.1

if I use vim to open file under cursor, suppose my vim cursor is now at word "NetworkManager", then vim will understand it as

"./NetworkManager/system"

that's why I want to add "\" before space, so the search result would be more vim friendly:)

I did try to change cscope's source code, but very difficult to fully achieve this. so have to do a post replacement:(

5 Answers

If you only want to do the replacements if there is a : present in the string, you can check if there are at least 2 columns, setting the (output)field separator to a colon.

Data:

cat file                                                                                                                                       michaelvandam@Michaels-MacBook-Pro
NetworkManager/system connections/Wired 1.nmconnection:14 address1=10.1.10.71/24,10.1.10.1
NetworkManager/system connections/Wired 1.nmconnection 14 address1=10.1.10.71/24,10.1.10.1%

Example in awk:

awk 'BEGIN {FS=OFS=":"}{if(NF>1)gsub(" ","\\ ",$1)}1' file

Output

NetworkManager/system\ connections/Wired\ 1.nmconnection:14 address1=10.1.10.71/24,10.1.10.1
NetworkManager/system connections/Wired 1.nmconnection 14 address1=10.1.10.71/24,10.1.10.1

This could be simply done in awk program, with your shown samples, please try following.

awk 'BEGIN{FS=OFS=":"} {gsub(/ /,"\\\\&",$1)} 1' Input_file

Explanation: Simple explanation would be, setting field separator and output field separator as : for this program. Then in main program using gsub(Global substitution) function of awk. Where substituting space with \ in 1st field only(as per OP's remarks it should be done before :) and printing line then.

This might work for you (GNU sed):

 sed -E ':a;s/^([^: ]*) /\1\n/;ta;s/\n/\\ /g' file

Replace spaces before : by newlines then replace newlines by \ 's.

Alternative using the hold space:

 sed -E 's/:/\n:/;h;s/ /\\ /g;G;s/\n.*\n//' file

Split the line on the first :.

Amend the front section, remove the middle and append the unadulterated back section.

My answer is ugly and I think RavinderSingh13's answer is THE ONE, but I already took the time to write mine and it works (It's written step by step, but it's a one line command):

I got inspired by HatLess answer:

first get the text before the : with cut (I put the string in a file to make it easy to read, but this works on echo):

cut -d':' -f1 infile

Then replace spaces using sed:

cut -d':' -f1 infile | sed 's/\([a-z]\) /\1\\ /g'

Then echo the output with no new line:

echo -n "$(cut -d':' -f1 infile | sed -e 's/\([a-z]\) /\1\\ /g')"

Add the missing : and what comes after it:

echo -n "$(cut -d':' -f1 infile | sed -e 's/\([a-z]\) /\1\\ /g')" | cat - <(echo -n :) | cat - <(cut -d':' -f2 infile)
Related