vim: paste block next to block - vim

I got this
______0______
/ \
__7__ __3__
/ \ / \
0 4 9 8
/ \ / \ / \ / \
7 7 0 4 6 0 3 2
______another______
/ \
__block__ __just__
/ \ / \
aside the first one
I'd like that
______0______ ______another______
/ \ / \
__7__ __3__ __block__ __just__
/ \ / \ / \ / \
0 4 9 8 aside the first one
/ \ / \ / \ / \
7 7 0 4 6 0 3 2
Is there kind of "mutliline block" copy/cut and paste in vim ?

There is no magical way to achieve that but it is doable with :help visual-block and some planning.
First, the naive approach, with visual-block mode:
Put the cursor on the first column of the line containing another.
Press <C-v> to enter visual-block mode, then jjjj to expand the block downward, and $ to expand it to the end of each line.
Cut it with d.
Move the cursor to the end of the line containing 0 and press p to put what you just cut.
The horror:
______0______ ______another______
/ / \ \
__7__ _ __block__ __just__ _3__
/ \ / / \ / \ \
0 4 9 aside the first one 8
/ \ / \ / \ / \
7 7 0 4 6 0 3 2
The problem is that putting "block text" (by lack of a better word) is done "in place", without adding padding or assuming anything about the user's intent.
In order to put that "block text" at the right position, you need to add some padding yourself:
Put the cursor on the first column of the line containing another.
Press <C-v> to enter visual-block mode, then jjjj to expand the block downward, and $ to expand it to the end of each line.
Cut it with d.
Move the cursor to the end of the line containing 0, append as many spaces as necessary with A<Space><Space><Space>, and press p to put what you just cut.
Much better:
______0______ ______another______
/ \ / \
__7__ __3__ __block__ __just__
/ \ / \ / \ / \
0 4 9 8 aside the first one
/ \ / \ / \ / \
7 7 0 4 6 0 3 2
NOTE: :help 'virtualedit' can be of use, too, but it can necessitate special care so I prefer the simplicity of adding padding manually.

Related

How to use a Unix sort command to sort by human-readable numeric file size in a column?

This question now answered - scroll to the end of this post for the solution.
Apologies if the answer is already here, but all the answers I have found so far suggest either the -h flag or the -n flag, and neither of those are working for me...
I have some output from a curl command that is giving me several columns of data. One of those columns is a human-readable file size ("1.6mb", "4.3gb" etc).
I am using the unix sort command to sort by the relevant column, but it appears to be trying to sort alphabetically instead of numercially. I have tried using both the -n and the -h flags, but although they do change the order, in neither case is the order numerically correct.
I am on CentOS Linux box, version 7.2.1511. The version of sort I have is "sort (GNU coreutils) 8.22".
I have tried using the -h flag in these different formats:
curl localhost:9200/_cat/indices | sort -k9,9h | head -n5
curl localhost:9200/_cat/indices | sort -k9 -h | head -n5
curl localhost:9200/_cat/indices | sort -k 9 -h | head -n5
curl localhost:9200/_cat/indices | sort -k9h | head -n5
I always get these results:
green open indexA 5 1 0 0 1.5kb 800b
green open indexB 5 1 9823178 2268791 152.9gb 76.4gb
green open indexC 5 1 35998 7106 364.9mb 182.4mb
green open indexD 5 1 108 11 387.1kb 193.5kb
green open indexE 5 1 0 0 1.5kb 800b
I have tried using the -n flag in the same formats as above:
curl localhost:9200/_cat/indices | sort -k9,9n | head -n5
curl localhost:9200/_cat/indices | sort -k9 -n | head -n5
curl localhost:9200/_cat/indices | sort -k 9 -n | head -n5
curl localhost:9200/_cat/indices | sort -k9n | head -n5
I always get these results:
green open index1 5 1 1021 0 3.2mb 1.6mb
green open index2 5 1 8833 0 4.1mb 2mb
green open index3 5 1 4500 0 5mb 2.5mb
green open index4 1 0 3 0 3.9kb 3.9kb
green open index5 3 1 2516794 0 8.6gb 4.3gb
Edit: It turned out there were two problems:
1) sort expects to see capital single letters - M, K and G instead of mb, kb and gb (for bytes you can just leave blank).
2) sort will include leading spaces unless you explicitly exclude them, which messes with the ordering.
The solution is to replace lower case with upper case and use the -b flag to make sort ignore leading spaces (I've based this answer on #Vinicius' solution below, because it's easier to read if you don't know regex):
curl localhost:9200/_cat/indices | tr '[kmg]b' '[KMG] ' | sort -k9hb
Your 'm' and 'g' units should be uppercase. GNU sort manual reads:
-h --human-numeric-sort --sort=human-numeric
Sort numerically, first by numeric sign (negative, zero, or positive); then by SI suffix (either empty, or ‘k’ or ‘K’, or one of ‘MGTPEZY’, in that order; see Block size); and finally by numeric value.
You can change the output of curl with GNU sed like this:
curl localhost:9200/_cat/indices \
| sed 's/[0-9][mgtpezy]/\U&/g'
| sort -k9,9h \
| head -n5
Yields:
green open index4 1 0 3 0 3.9kb 3.9kb
green open index1 5 1 1021 0 3.2Mb 1.6Mb
green open index2 5 1 8833 0 4.1Mb 2Mb
green open index3 5 1 4500 0 5Mb 2.5Mb
green open index5 3 1 2516794 0 8.6Gb 4.3Gb
Other letters like "b" will be treated as "no unit":
green open indexA 5 1 0 0 1.5kb 800b
green open indexE 5 1 0 0 1.5kb 800b
green open indexD 5 1 108 11 387.1kb 193.5kb
green open indexC 5 1 35998 7106 364.9Mb 182.4Mb
green open indexB 5 1 9823178 2268791 152.9Gb 76.4Gb
If so desired, you can change the units in the sorted output back to lowercase by piping to sed 's/[0-9][MGTPEZY]/\L&/g'
sort does not understand kb, mb and gb. You have to use K, M and G. You can use tr to convert the suffixes:
curl localhost:9200/_cat/indices | tr 'kmgb' 'KMG ' | sort -b -k 9 -h

Print a selective column after subtraction from another file

I have two files with equal number of rows and columns. I would like to subtract the 2nd column in one file from the 2nd column in another file without considering the missing values. e.g.
ifile1.txt
3 5 2 2
1 ? 2 1
4 6 5 2
5 5 7 1
ifile2.txt
1 2 1 3
1 3 0 2
2 ? 5 1
0 0 1 1
Here "?" is the missing value and should not be considered in computation.
ofile.txt i.e. [$2(ifile1.txt) - $2(ifile2.txt)]
3
?
?
5
I could able to do it without any missing values in following way. But can't able to succeed with a missing value like here "?".
paste ifile1.txt ifile2.txt > ifile3.txt
awk '{n=NF/2; for (i=1;i<=n;i++) printf "%5.2f ", $i-$(i+n); print ""}' ifile3.txt > ifile4.txt
awk '{printf ("%.2f\n",$2)}' ifile4.txt > ofile.txt
$ awk 'NR==FNR{a[NR]=$2;next} {print ((a[FNR]$2)~/?/ ? "?" : a[FNR]-$2)}' file1 file2
3
?
?
5
POSIX shell script, and paste.
paste ifile[12].txt | \
while read a b c d e f g ; do \
[ "$b$f" -eq "$b$f" ] 2> /dev/null \
&& echo $(( b - f )) \
|| echo '?' ; \
done
Output:
3
?
?
5

Insert same character in nth lines with vim

I want to insert a sequence of numbers but I need to repeat every number in n lines, I mean:
Original file New file
1 1,1
2 1,2
3 1,3
4 2,4
5 2,5
6 2,6
7 3,7
8 3,8
9 3,9
You can use a :help sub-replace-expr. A simple .* will match the number, and you can then concatenate the result, using submatch(0) to work with the match:
:%s#.*#\=(submatch(0)+2)/3 . ',' . submatch(0)#

Why use 0d_ in DiffOrig in Vim?

In the online manual of Vim, :help DiffOrig
will show the recommended command sequence to get changes of current editing file.
Here it is:
command DiffOrig vert new | set bt=nofile | r # | 0d_ | diffthis
\ | wincmd p | diffthis
I wonder what the effect of 0d_ is. I tried 0d_ in normal mode, it works like dd, but I can't understand why it used here.
Let's explain it a bit: Suppose you have original foo.txt containing (with line numbers):
1 a
2 c
3 d
~
You have added a line containing “b” between lines 1 and 2:
:vert new creates a new, empty, buffer in a vertical split (:help :new)
:set bt=nofile makes it a scratch buffer (:help 'bt'). Note:
1 a | 1 ·<cursor here
2 b | ~
3 c | ~
4 d | ~
~ | ~
:r # inserts after current line, contents of alternate file (#), as stored on the file system. You haven't saved the other buffer, so you get original content. (:help alternate-file).
:help :r tells you that it always inserts after. Therefore:
1 a | 1
2 b | 2 a
3 c | 3 c
4 d | 4 d
~ | ~
:0d_ removes the first line. Why 0, I don't know it really, I would rather
write it :1d_. :help range tells:
When using a 0 (zero) this is interpreted as a 1 by most commands
The _ specifies that it goes to the black-hole register. See
:help :d about the :d ex command, it works linewise.
The rest is obvious.

gnuplot missing data with expression evaluation

I want to use the plot command in gnuplot with expression evaluation, i.e.
plot "-" using ($1):($2) with lines
1 10
2 20
3 ?
4 40
5 50
e
But I want it to ignore the missing data "?" in such a way that it connects the line (and doesn't break it between 2 and 4).
I tried set datafile missing "?",
but in agreement with the online-help it does not connect the lines. The following would, but I cannot use expression evaluation:
plot "-" using 1:2 with lines
1 10
2 20
3 ?
4 40
5 50
e
Any ideas how to connect the lines and use expression evaluation?
Two column data
If you set up a data file Data.csv
1 10
2 20
3 ?
4 40
5 50
you can plot your data with connected lines using
plot '<grep -v "?" Data.csv' u ($1):($2) w lp
More than two column data
For more than two columns you can make use of awk.
With a data file Data.csv
1 10 1
2 20 2
3 ? 3
4 40 ?
5 50 5
you can run a script over the data file for each plot like so:
plot "<awk '{if($2 != \"?\") print}' Data.csv" u ($1):($2) w lp, \
"<awk '{if($3 != \"?\") print}' Data.csv" u ($1):($3) w lp
A reference on scripting in gnuplot can be found here. The awk user manual here.

Resources