3

When I edit some code, I have a repl aside which gives me useless imports/includes, and I'd like to remove them in one command.

To be concrete, I have the following text:

import A
import B
import C
import D
import E
import F
import G

And I would like to remove lines 1, 3, 4, and 7.

I have tried :1,3,4,7 but it does not work (because these are ranges). Is there a way to do it in one command?

1
  • If all the lines you want removed include a unique pattern then it might be easier to use ::g/<pattern>/d
    – user25109
    Dec 24, 2021 at 10:55

4 Answers 4

3

I came up with this:

:for i in reverse([1, 3, 4, 7]) | exe i . 'delete' | endfor

This could easily be put into a function that could be called:

function DeleteLines(lines)
    let lines = reverse(uniq(sort(a:lines, 'n')))
    for i in lines
        if i > line('$')
            echohl WarningMsg
            echomsg "Warning: Line number " . i . " is beyond the end of the file."
            echohl None
            continue
        endif
        exe i . 'delete'
    endfor
endfunction

Then you can delete lines specified in any order you like:

:call DeleteLines([7, 1, 4, 3])
2

No, it is not really possible. Besides the way @Heptite mention, you can do it in 1 command interactively like this:

:%s/^import.*\n//c

This will ask for confirmation of the line to be deleted. Adjust the search pattern to taste.

1

If you simply want to delete lines 1, 3, 4, and 7 this should do the trick:

:g/\v%1l|%3l|%4l|%7l/d

This uses the g command in vim to find all lines that match the given regex. The regex enables very magic at the beginning ofnthe regex with \v making it so that regex branches normally delimited with \| can now be delimited with simply |, as well as various regex atoms in Vim starting with %. Then the regex then uses the %[n]l regex atom which matches anywhere on line n. This yields a regex which matches any position on lines 1,3,4, or 7. Then we filter lines with this regex using the g command and run d to delete them.

However this isn't really ideal because if for some reason there was a new import before import A you'd now be deleting that import and imports B, C, and F, instead of imports A, C, D, and G. For this particular example perhaps something like this would work better:

:g/\v^\s*import\s+(A|C|D|G)>
2
  • You don’t need to group the first regex, which saves some typing
    – D. Ben Knoble
    Dec 24, 2021 at 14:30
  • @D.BenKnoble Ah, yeah not sure why I had the regex group in there. Thanks for the tip! Updated the answer with it
    – cachehash
    Dec 28, 2021 at 21:47
0

Assuming the Bash, Ksh or Zsh shell,

  • From inside Vim:

    :%!sed -e{1,3,4,7}d
    
  • From the shell itself:

    sed -e{1,3,4,7}d file
    
  • Assuming a Sed that supports -i, from the shell itself with in-place editing (i.e., the changes are written to the file rather than only being output):

    sed -ie{1,3,4,7}d file
    

If the number of lines you want to keep is smaller than the number of lines to delete, it is better to use

sed -ne{2,5,6}p file

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.