Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

First occurrence on every line vi/vim/sed etc

Tags:

regex

vim

vi

sed

awk

Using VI replacing the first occurrence/instance is pretty simple.

    :%s/search/replace/args

but, here is my data set in a .csv format/file:

"192.168.2.1","www.google.com","2009/01/11_10:00"," What a great website"
"192.168.2.2/driving/is/fun","-","2009/03/22_00:00","Driving website"
"192.168.2.4/boating/is/crazy","-","2009/03/22_00:00","Boating Website"
"192.168.2.5","www.cars.com","2009/04/27_00:00","What a good car website"

so, you'll notice in the first line, there are 4 columns, this is the ideal line for the .csv format.

However, in the second line, there are 4 columns, but the first column only accepts ip addresses and nothing more, so 192.168.2.2/driving/is/fun must be removed or seperated with a "," .csv delimter.

In vi, I was able to use the following:

    :/^"\d\{,3}\.\d\{,3}\.\d\{,3}\.\d\{,3}\//s/\//","/

which does the following:

  • /^"\d{,3}.\d{,3}.\d{,3}.\d{,3}/ - Sets an anchor to start the search at the first IP with a forward slash /. For example, line 2: "192.168.2.2/

  • /s///","/ - replaces the / at the end of the IP address and substitutes it with a .csv delimiter ","

This works great in VI/VIM, replaces exactly what I need one line at a time. However, the data set is much much larger and manually using the following vi search and replace is time consuming. I am looking to script it or find an alternative solution because VI/VIM will only do it one line at a time, the following :s/search/replace/g replaces every / on the line changing the date column in addition.

Obviously, I've tried the following:

Adding the % for the whole file inside of the start of the substitution like so:

    :/^"\d\{,3}\.\d\{,3}\.\d\{,3}\.\d\{,3}\//%s/\//","/

which highlights every entry I need to modify but errors out:

    E492: Not an editor command: /^"\d\{,3}\.\d\{,3}\.\d\{,3}\.\d\{,3}\//%s/\//

which is rather confusing.

I would ultimately like to use sed/perl to script the editing of the whole file in one shot.

so..

"192.168.2.2/ --> "192.168.2.2","

First occurrence on every line.

Any help will be greatly appreciated..

Thanks!

like image 374
SecurettyPhreak Avatar asked Jan 17 '23 10:01

SecurettyPhreak


2 Answers

In vi/vim you can specify the search range that you want to replace over. In this case you want :%s to replace in all lines:

:%s/search/replace/g

You can also specify:

:2,5s/search/replace/g      Replace on lines 2-5
:.,$s/search/replace/g      Replace from current line (.) to last line ($)
:.,+3s/search/replace/g     Replace on the current line (.) and the two next lines (+3)
:g/^asd/s/search/replace/g  Replace on lines starting with 'asd'. 

You can then combine this with a simpler pattern to make the replacements you want throughout the whole file:

:%s/^\("[^/"]*\)[^"]*"/\1"/

This will remove everything after the IP address from the first entry in the CSV.

:%s/^\("[^/"]*\)\/\([^"]*\)"/\1","\2/

This will split the first entry into the IP address and the remainder, though this will only be done for those lines where there is a slash after the IP. What you were trying to do was find the pattern, go to that line and then replace. Adding the '%' in that case made the command invalid.

like image 109
John Lawrence Avatar answered Jan 18 '23 23:01

John Lawrence


In ViM, try:

 :%s/^\("\d\{,3}\.\d\{,3}\.\d\{,3}\.\d\{,3}\)\(\/[^"]\)/\1","\2

That is, instead of a search/substitute I use a global (% is shortcut for 1,$ i.e from first line to last line) substitution. I moved your search pattern into the substitution pattern and capture the ip address and the path in separate groups. Then replace them back, squeezing "," in between.

like image 29
PEZ Avatar answered Jan 19 '23 00:01

PEZ