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
.
Top comments (3)
To create the file with 1000 copies of that block, just simply
999P
from the first line is enough, no? No need for a longfor
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!
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.
I have used a stackoverflow question just to show how powerful vim is, how fast you can make complex changes in files.