How to delete a particular line which has occurred many times in the file in vim - vim

I want to delete a line: This is an example, which occurs multiple times in a file. How do I go about it.
Thanks,
Alisha

You could do:
:g/This is an example/d

:%s/This is an example\n//gc
% indicates all lines of a file
s indicates pattern to be searched.
g for global replacement
c for confirmation on each replace

If you want to delete the lines containing only the exact match you could:
:g/^This is an example$/d

You can do this using an external command:
:%!grep -v "This is an example"
This filters the entire file through the given command. The grep -v command selects all the lines of the file that do not match the given regular expression.

Related

why is vim's delete command so slow

I have a file that contains about 5000 lines and I want to delete all lines that have 'some_string' so I first search for /some_string then I execute :g//d. This takes over 5 minutes to delete ~90% of the lines. What gives?
In comparison, if I run sed -i '/some_string/d' some_file it takes 46ms.
Add an underscore to your command.
I experienced a similar problem and it turned out to be each line being copied to my system clipboard. By adding a _, you tell vim to use the blackhole register.
:g//d_
The help gives the following syntax for :d
:[range]d[elete] [x] Delete [range] lines (default: current line) [into register x].

Edit conf file linux under specific section

I have a file that I want to change from command line. The thing is that it has sections and in some different sections it has the same values that I need to change.
The file looks like:
...
[DEFAULT]
findtime = 600
maxretry = 3
[ssh]
maxretry = 6
And I want to change only the maxretry under [DEFAULT].
Maybe there is a conifuration command line that searches the section in config file and changes value named X ?
The command I wrote with sed changes all occurences and I want only the first occurence after [DEFAULT]
sudo sed -i "s/\(^maxretry =.*$\)/maxretry = ${NUMBER_OF_RETRIES}/" filename
Appreciate your help.
Thanks
One way using awk:
$ NUMBER_OF_RETRIES=5
$ awk '/^\[DEFAULT\]/{f=1;}f && /^maxretry =/{print "maxretry = "x;f=0;next}1' x=$NUMBER_OF_RETRIES file
First, we search for the DEFAULT section, and once found, set a flag. Search for the line beginning with maxretry, and if flag is set, do the replacement.
You can check a default flag, which tells you if a substitution occurred or not:
awk '!f && /^maxretry =.*$/ {$0="maxretry = 666"; f=1} 1'
Note that this will not write the change in the file, just redirect the output to a new file or do smth similar. This approach is very specific and works only for first occurrence. #Guru's answer is more generic and can work for arbitrary section (e.g. you want to replace the 2nd,3rd occurrence depending on the section). Nevertheless this example is simpler when targeting the first occurrence.

What is the shorthand for the first argument of the previous comment in bash? last is '$!'

What is the special character which indicate first ?
if we do
$ vi .bashrc
$ source !$
this !$ will replaced by .bashrc
because ! means previous line(am I correct?), $ means last word (for sure)
then what is first?
I want to insert some string in every line in vi editor using
:%s/find-key-word/replaced-keyword/g
in here, if I put
:%s/$/example/g
in vi editor, it will append in all lines with example.
I want to insert all in front of all string every line.
I know I can use visual block (ctrl+v) and select all front lines and insert (shift+i) insert some word and escape(esc) will do the same... but I want to do in one shot..
please let me know how to do..
Thanks in advance
There are two questions, so you are getting two kinds of answers :)
The bash command history has only a passing similarity to the vi regular expression syntax.
^ is the beginning of line in vi. $ is the end of line in vi.
!!:0 is one way of accessing the first word of the previous command in bash
!$ is one way of accessing the last word of the previous command in bash
To indicate beginning of line, the symbol used is:
^
See an example:
$ cat a
hello!
this is me
testing some
stuff
$ sed 's/^/XXX/' a
XXXhello!
XXXthis is me
XXXtesting some
XXXstuff
The character you are looking for is ^.
For example, :%s/^/example/g will prepend all lines with the string example.
In bash, !^ refers to the first argument of the previous command, and !$ the last argument.

Efficient way to refactor a class/method/string within a directory using vim

So far, I have been manually refactoring code by using the find-and-replace operation
%s:/stringiwanttoreplace/newstring/g
in vim.
But this is a slow and laborious process if I have stringiwanttoreplace in many files inside a specific directory.
My current/typical slow and laborious process involves a grep:-
grep -rn "stringiwanttoreplace" .
in my terminal to reveal all the locations/filenames where stringiwanttoreplace are; and now that I know which files contain stringiwanttoreplace, I will open each file one-by-one to perform the find-and-replace operation in each file.
Is there a more efficient workflow (in vim) to get this done?
CLARIFICATION: I would prefer a vim-based solution instead of a bash script/one-liner.
Here's the full sequence of commands that I would use:
/stringiwanttoreplace
:vimgrep /<c-r>// **
:Qargs
:argdo %s//newstring/g
:argdo update
In the first line, we search for the target pattern. That populates the last search pattern register (:help quote/), which means that we won't have to type it out in full again.
The :vimgrep command searches the entire project for the specified pattern. Type <c-r>/ as ctlr+r followed by / - this inserts the contents of the last search pattern register onto the command line. The first and last / symbols are delimiters for the search field. The trailing ** tells Vim to look inside every file and directory below the current directory.
At this point, the quickfix list will be populated with search matches from all matching files. :Qargs is a custom command, which populates the argument list with all of the files listed in the quickfix list. Here's the implementation:
command! -nargs=0 -bar Qargs execute 'args ' . QuickfixFilenames()
function! QuickfixFilenames()
" Building a hash ensures we get each buffer only once
let buffer_numbers = {}
for quickfix_item in getqflist()
let buffer_numbers[quickfix_item['bufnr']] = bufname(quickfix_item['bufnr'])
endfor
return join(values(buffer_numbers))
endfunction
Add that to your vimrc file.
Having run :Qargs, our argument list should now contain all of the files that include our target string. So we can run the substitution command with :argdo, to execute the command in each file. We can leave the search field of the substitution command blank, and it will automatically use the most recent search pattern. If you want, you could include the c flag when you run the substitution command, then you'll be prompted for confirmation.
Finally, the :argdo update command saves each file that was changed.
As #Peter Rincker pointed out, you should ensure that Vim's 'hidden' option is enabled, otherwise it will raise an error when you try to switch to another buffer before writing any changes to the active buffer.
Also, note that the last 3 commands can be executed in a single command line, by separating them with a pipe character.
:Qargs | argdo %s//replacement/gc | update
The :Qargs command is pinched from this answer (by me), which in turn was inspired by this answer by DrAl. A very similar solution was posted by #ib, which suggests to me that Vim should really implement something like :quickfixdo natively.
If you really want to do it in Vim you can follow the suggestions here.
You can call this from within Vim (:!find ...) but you don't need to:
find . -type f | xargs sed -i 's/stringiwanttoreplace/newstring/g'
Fine-tune the file selection with the dozens of parameters described in
man find
(e.g., replace only in HTML files: -name \*.html)
This solution will try to attempt the replacement in all files. You can filter that through grep before, but that is just doing twice the work for no gain.
By the way: sed uses almost the same syntax for regular expressions as Vim (stemming from the same history).
You could open all the files and type
:bufdo :s/stringiwanttoreplace/newstring/g
It performs the search/replace in all your buffers.
You don't need vim to do this, you can use command line tools. Using sed in a loop on the list of files to do this for you automatically. Something like this:
for each in `grep -l "stringiwanttoreplace" *` ;
do
cat $each | sed -e "s/stringiwanttoreplace/newstring/g" > $each
; done
vim7 has recursive grep built-in
:vimgrep /pattern/[j][g] file file1 file2 ... fileN
the result will be shown in a quickfix-window (:help quickfix)
to do the search recursively use the **-wildcard like
**/*.c to search through the current folder and recursively through all subdirectories.

Linux rename function not being used correctly

I'm trying to use the rename command in a Terminal in Ubuntu to append a string to the beginning of some avi file names as follows.
rename -n 's/(\w)\.avi$/String_to_add__$1\.avi/' *.avi
So I expect the following:
String_to_add_MyMovie.avi
Problem is that when I run the command it appends the string to the end of the file name, so I end up with the following:
MyMovie_String_to_add_.avi
I'm not sure if I have the perlexpr syntax wrong or something else. Any insight is appreciated.
UPDATE:
Thanks for the suggestions, I tried the suggestions from alno and plundra and made the following modification:
rename -n 's/(\w+)\.avi$/String_to_add__$1\.avi/' *.avi
But now the file gets the string inserted in the middle of the name as follows:
My_String_to_add_Movie
My apologies though, I neglected to mention that the titles are preceded by 3 numeric values, so the file name nomenclature is {3 numbers}-My_Movie.avi so for example 001-My_Movie.avi. But I didn't think this would make a difference since I'm assuming \w+ matches alphanumeric characters, might the '-' be the issue?
Haven't tried Christian's approach yet, I want to be able to use the rename command, or at least understand why it's not working before I try a different approach.
I don't think rename -n is standard. You could do this:
for i in *.avi; do mv $i String_to_add_$i; done
You're only matching a single character with \w, you want \w+, so the complete line would be:
rename -n 's/(\w+)\.avi$/String_to_add__$1\.avi/' *.avi
Correct version:
rename -n 's/(\w+)\.avi$/String_to_add__$1\.avi/' *.avi
You simply forgot + after \w, so it tried to match only one character.

Resources