DEV Community 👩‍💻👨‍💻 is a community of 967,611 amazing developers

We're a place where coders share, stay up-to-date and grow their careers.

Sérgio Araújo

Posted on • Updated on

The problem:

I have a block in a yaml file that I would like to yank and paste several times:

``````- probeNumber: 1
probeLocation: [0, 0, 0.1]
``````

Is it possible to automatically increment the value of probeNumber and probeLocation in each block? Like so:

``````- probeNumber: 1
probeLocation: [0, 0, 0.1]

- probeNumber: 2
probeLocation: [0, 0, 0.15]

- probeNumber: 3
probeLocation: [0, 0, 0.20]
``````

probeLocation is not an integer, it is incremented by a fixed value in each block (0.05). I need 1000 or so of these blocks so doing this manually is not feasible.

fast and magic solution (creating the file):

Just select the 3 first lines (we need at least one blank line between each block), copy to the clipboard and run:

``````:for i in range(999) | silent! 0put + | endfor
``````

The second problem

Now increasing the numbers to fit your needs

In order to increase `probeNumber` lines:

``````:let c=1 | g/\d\+\$/ s//\=c/ | let c+=1
``````

Now the lines with `probeLocation`:

``````:let c=0.10 | g/0\.1\ze]/ s//\=printf("%0.2f", c)/ | let c+=0.05
``````

In the above global commands we are using a counter `c=1` and increasing it. At the substitution part we are usig an expression register `\=something`. On the `printf` function we are converting the counter to a float point number with two digits. On each line of the global pattern we are also increasing the counter by `0.05`.

Substitute spaces for dashes but not on entire line:

Supose you have these lines and want to remove spaces only i the name of the files

``````cp 01-file with spaces.txt \$HOME/tmp/01-file with spaces.txt
cp 02-file with spaces.txt \$HOME/tmp/02-file with spaces.txt
``````

One regex to match only the filenames could be:

``````/\d\+-[^.]*
``````

The solution the will be:

``````%s/\d\+-[^.]*/\=substitute(submatch(0), ' ', '-', 'g')/g
``````

Or if you have something like:

``````Time in hours, minutes and seconds which I want to substrat 00:04:01
Time in hours, minutes and seconds which I want to substrat 00:05:01
Time in hours, minutes and seconds which I want to substrat 00:06:12
Time in hours, minutes and seconds which I want to substrat 00:14:01
Time in hours, minutes and seconds which I want to substrat 00:00:01
``````

And you want to decrease 10 seconds in every match:

``````:%s/00.*\ze\$/\=system('date -u -d "'.submatch(0).' +0000 -10 sec" +"%H:%M:%S"')/g
``````

I have created a script called less2sec that uses the date command above and have a default second decrease '02' and a default hour, just to give the user an example. Take a look on the script:

``````#!/bin/env bash
# Bash script to decrease [defaut 02] sec
# Last Change: Tue, 31 May 2022 15:52
# vim: ft=sh

# Note: I had to remove the clear command because it
# puts some trash on my final output I use on vim
# https://unix.stackexchange.com/a/564986/3157

HELP(){
cat <<-EOF
HELP
-------------------------------
Subtract seconds from HH:MM:SS"
-------------------------------
\${0##*/} [-h] [hora] [segundos]

EOF
}

[ "\$1" == "-h" ] && HELP && exit 1

[ "\$1" ] && hora="\$1"  || hora="11:17:00"
[ "\$2" ] && param="\$2" || param="02"

# echo -e "\t\${0##*/} Script para subtrair segundos"
# echo -e "\tImprimindo \$hora menos \$param segundos:"
hora=\$(date  -u -d"\$hora +0000 -\$param sec" '+%H:%M:%S')

# here we are using "printf" to avoid  the new line character
printf "%s" "\$hora"
``````

We have to add a space after the script name and befor the amount of seconds we want to decrease.

``````:%s/.*/\=system('less2sec ' . submatch(0) . ' 10')
``````

The only catch is that your regex, the search part, must match a column of text like this: `00:01:00`.

Give me some feedback, some insight to improve this article or correct any possible mistake.

Filipe Brandenburger

To create the file with 1000 copies of that block, just simply `999P` from the first line is enough, no? No need for a long `for` loop there...

The stuff with incrementing a Vimscript variable from a `:g` and using it in a `:s` for the second part is genius! Very nice solution.

Great article!

Sean Allin Newell

I mean... If you really need something like this wouldn't helm, go templating, or another higher level yaml+k8s abstraction work?

BUT.
If we must have a big ol hand cranked yaml file, then yeah, this is the shit.

Sérgio Araújo

I have used a stackoverflow question just to show how powerful vim is, how fast you can make complex changes in files.

🌚 Friends don't let friends browse without dark mode.

Sorry, it's true.