why the vim :g command is called "global" command ? any history for it ? - history

Just curious what "global" here means ?
is it related to the g option in regular expression ?
some freind told me it origins from ed, any one can explain a little bit on that ?

vi is inspired by ex, ex is inspired by ed, ed is inspired by qed
ed was hacked together by Ken Thompson way back in the 1971 — basically he put regex in qed (he did more, but it's outside the scope of this answer.)
One command in ed was the "g" or "global" command. It allowed you to operate on all lines in the file at once.
Grep is actually named for one of the uses of this command g/re/p (g global, re regular expression, p print) in ed this command was used like g/bash/p to print out all lines containing the word bash — this was taken out of ed and made into a standalone function (according to Doug McIlroy, he asked Ken to do it for him & Ken left it on his desk the next morning)

Related

vim: Run multiple commands based off of one :global command

Apologies if this has been posted already, for I cannot find an answer, even on the vim wiki.
Is there a way I can run multiple commands in vim command-line mode off of a single :g search?
For example,
:%g/foo/ s/bar/\=#a/g | exe "norm /cat\<enter>\"ayiw"
Which (for what I intend it to do) should, on every line matching foo, replace bar with the contents of register a, and then find the next iteration of cat (even if it is many lines ahead), and put the surrounding word into register a.
Instead, this specific syntax completes the subsitution command using the current contents of the initial a register, and then executes the normal mode command on a single line (after the substitution has been completed).
This example is not my specific use-case but shows one instance where this functionality is useful. I realize I could put it all into a single exe, i.e., %g/foo/exe "norm :s/bar/\\=#a/g\<enter>/cat\<enter>\"ayiw", but I would like to do it the first way, as I feel it is more flexible.
I would prefer to do this using vanilla vim, but if a plugin exists for this, that is an okay alternative. Does anybody know if there is syntax to do such a thing?
Okay a "little bit" dirty, but does this work for you?
:let list = split(execute('g/cat/p'), '\n') | g/foo/ s/bar/\=matchstr(remove(list, 0), '\s\d\+\s\zs.*')/g
It first reads all occurences of cat save them in a list.
Then replace the first bar with the first cat... and so on.
The dirty part ist the matchstr command. the g//p also returns a number for the result so the list looks like this:
1 cat
2 cat
3 cat
...
that's why we have to remove a bit from the front. I would love to hear if someone knows a clean solution for that (I am also interested in a clean vimscript solution, does not have to be a oneliner).
You can do this (at least for multiple :s commands applied to a single :g). Example:
" SHORT STORY TITLES to single word of CapitalizedWords within <h3>s
.,$g/^\L\+$/s/[^A-Z0-9 ]\+//ge|s/\u\+/\L&/ge|s/\<\l\+\>/\u&/ge|s/ \+//ge|s/.*/<h3>&<\/h3>/

How to edit this file using grep or using cat or using vim or using another tool?

One of my elder brother who is studying in Statistics. Now, he is writing his thesis paper in LaTeX. Almost all contents are written for the paper. And he took 5 number after point(e.g. 5.55534) for each value those are used for his calculation. But, at the last time his instructor said to change those to 3 number after point(e.g. 5.555) which falls my brother in trouble. Finding and correcting those manually is not easy. So, he told me to help.
I believe there is also a easy solution which is know to me. The snapshot of a portion of the thesis looks like-
&se($\hat\beta_1$)&0.35581&0.35573&0.35573\\
&mse($\hat\beta_1$)&.12945&.12947&.12947\\
\addlinespace
&$\hat\beta_2$&0.03329&0.03331&0.03331 \\
&se($\hat\beta_2$)&0.01593&0.01592&0.01591\\
&mse($\hat\beta_2$)&.000265&.000264&.000264 \\
\midrule
{n=100} & $\hat\beta_1$&-.52006&-.52001&-.51946\\
&se($\hat\beta_1$)&.22819&.22814&.22795\\
&mse($\hat\beta_1$)&.05247&.05244&.05234\\
\addlinespace
&$\hat\beta_2$&0.03134&0.03134&0.03133 \\
&se($\hat\beta_2$)&0.00979&0.00979&0.00979\\
&mse($\hat\beta_2$)&.000098&.000098&.000098
I want -
&se($\hat\beta_1$)&0.355&0.355&0.355\\
&mse($\hat\beta_1$)&.129&.129&.129\\
......................................................................
........................................................................
........................................................................
Note: Don't feel boring for the syntax(These are LaTeX syntax).
If anybody has solution or suggestion, please provide. Thank you.
In sed:
$ sed 's/\(\.[0-9]\{3\}\)[0-9]*/\1/g' file
&se($\hat\beta_1$)&0.355&0.355&0.355\\
&mse($\hat\beta_1$)&.129&.129&.129\\
ie. replace period starting numeric strings with at least 3 numbers with the leading period and three first numbers.
Here is the command in vim:
:%s/\.\d\{3}\zs\d\+//g
Explanation:
: entering command-mode
% is the range of all lines of the file
s substitution command
\.\d\{3}\zs\d\+ pattern you would like to change
\. literal point (.)
\d\{3} match 3 consecutive digits
\zs start substitution from here
\d\+ one or more digits
g Replace all occurrences in the line
Concerning grep and cat they have nothing to do with replacing text. These commands are only for searching and printing contents of files.
Instead, what you are looking is substitution there are lots of commands in Linux that can do that mainly sed, perl, awk, ex etc.

vim substitute mulitple characters in a line

Command :%s:a:b will modify line aaa to line baa. The question is how to get result bbb using only one command (not using :%s:a:b 3 times, what I am doing now :-) ).
You need to add g flag at the end, like this:
:%s:a:b:g
When working with regular expressions this flag commonly means a "global" replacement, i.e. replace all occurrences.
The same technique usually works in other tools too that use regular expressions, for example sed, perl, etc.
UPDATE
I am surprised that such a simple answer still keeps receiving upvotes... So for you vim fans out there I recommend this great site where I still keep learning interesting new stuff: http://vimcasts.org/
remember the 'e' flag
:%s:a:b:e
Have a look at this answer Multiple search and replace in one line

How to repeat the same search and replace command over disjunct line ranges in Vim?

I had a situation where I wanted to replace FOO with BAR through out a file. However, I only want to do it in certain places, say, between lines 68–104, 500–537, and 1044–1195. In practice, I dropped markers at the lines of interest (via ma, mb, mc, etc.) and ran the following:
:'a,'b s/FOO/BAR/g | 'c,'d s/FOO/BAR/g | 'e,'f s/FOO/BAR/g
I had to repeat this dozens of times with different search and replace terms s/CAT/DOG, etc., and it became a pain to have to rewrite the command line each time. I was lucky in that I had only three places that I needed to confine my search to (imagine how messy the command line would get if there were 30 or 40).
Short of writing a function, is there any neater way of doing this?
On a related note. I copied FOO to the s (search) register, and BAR to the r (replace) and tried running
:'a,'b s/\=#s/\=#r/ | 'c,'d s/\=#s/\=#r/ | 'e,'f s/\=#s/\=#r/
This would have saved me having to rewrite the command line each time, but, alas, it didn’t work. The replace bit \=#r was fine, but the \=#s bit in the search pattern gave me an error.
Any tips would be appreciated.
If you need to perform a set of line-wise operations (like substitutions) on a bunch of different ranges of lines, one trick you can use is to make those lines look different by first adding a prefix (that isn't shared by any of the other lines).
The way I usually do this is to indent the entire file with something like >G performed on the first line, and then use either :s/^ /X/ commands or block-visual to replace the leading spaces with X on the lines I want.
Then use :g in conjunction with :s. eg:
:%g/^X/s/FOO/BAR/g
:%g/^X/s/BAZ/QUUX/g
Finally, remove the temporary prefixes.
In order to get rid of the necessity to retype the same search
pattern, substitution string and flags, one can simply use the
:& command with the & flag:
:'a,'bs/pat/str/g | 'c,'d&& | 'e,'f&&
(See :help :& for details.)
Instead of using marker use this one :
:68,104s/FOO/BAR/g << substitue from line 68 to 104
This should make your job a little bit easier and clearer.
inspired by #Vdt's answer:
I am not sure but you could write all the substitutions down in a file and source that file i think.
substitutions.vim:
68,104s/FOO/BAR/g
168,204s/FOO/BAR/g
618,644s/FOO/BAR/g
681,1014s/FOO/BAR/g
.
.
.
68,104s/BAZ/BOOO/g
168,204s/BAZ/BOOO/g
and then :so substitutions.vim maybe you can also use this for multiple files of same structure. you can add an e to add an ignore error message, if it is not clear that the substitutions are found on the corresponding line blocks.
With q:, you can recall previous command lines and edit them as a normal Vim buffer, so you can quickly replace FOO and BAR with something else, then re-execute the line with Enter.
The s/\=#s/\=#r/ doesn't work; as you said, this only works in the replacement part. But for the pattern, you can use Ctrl + R Ctrl + R s to insert the contents of register s, instead of \=#s. Preferably use the default register, then it's a simple s//, but you probably know that already.
When performed over a closed fold, substitutions are limited to that fold.
fold each region
put the cursor on one closed fold
perform the substitution: :s/foo/bar<CR>
move to the next closed fold with zj or zk
use the command-line history: :<C-p><CR> or :<Up><CR> to perform the same substitution
repeat…
You can also add the c flag at the end of your substitution so that Vim asks you for a confirmation before actually performing it. This can be tedious if you have lot of matches.
Here's the simplest way to do it
:5,10s/old/new/g
5,10 : startlinenum,endlinenum

:g showing functions and comments below

I'm not sure if this can be accomplished with regex, so here goes and hoping for the best.
If in vim I do,
:g/function
I get a list of all function rows.
Now, I'd like that but with comments (!) below until the first non comment row, so I get something like:
3 function MyFunction()
4 !This is a comment
5 !This is also a comment
23 function MyOtherFunction()
24 !This is a comment
25 !This is also a comment
Something like that possible ?
Yes
:g/^func/.;/^[^!]/-1 print
Update
An explanation was suggested...so here goes... vi(1) is powerful in part because it is a cursor-addressing extension to Ken Thompson's original line-oriented ed(1) editor. (ed(1) and its spinoff ex is still available on Linux after all these years, albeit in clone form like vi itself.) ed and its early-unix siblings were the first programs anywhere to use regular expressions.
Ok, create a file with 26 or so lines, one for each letter of your alphabet and start vi, ed, or ex. (For ed or ex, leave out the : characters.) Try:
:1;/m/p
The general form of a vi command is: addr, addr2 commmand
In my example the command is just p for print. addr1 and addr2 are usually a line number or a regular expression using /re/ to search downward or ?re? to search upward. Try /c/;/g/p which prompts me to explain: the ; causes the editor to switch to the line found by the first address before it evaluates the second address. It doesn't always matter in the default wrapscan mode but if you type :set nows (not in ed) then search patterns won't wrap and the difference between , and ; becomes bigger.
The most important line mode command wasn't used in my example but it should be mentioned here: :s/pattern/replacement/ or :s/pattern/replacement/g. This command can of course take addresses so a typical command is 1,$s/old/new/g The $ identifies the last line. The default address for most commands is the current line but for the global or g command it defaults to 1,$ and has the general form
addr1, addr2 g /pattern/ any_linemode_command
For example, say I'm Jeff but I want to blame Joel for different types of critical errors in the logs. I need to be stealthy and not change the Jeff's on mere warning lines, so I need:
g/critical.*error/s/Jeff/Joel/
That will run the substitute command on every line of the file that has the pattern "critical anything error" and then just change Jeff to Joel.
So now the answer should be fairly clear. The command works as follows: on every line of the file, check to see if the line begins with /^func/ (func at the beginning of the line) and if it does, start with . (the current line) then, resetting the current address to that line (;) search for a line that does NOT begin with !, and if it's found, subtract one from the line number found (back up slightly to the last actual comment) and then just run the print command.

Resources