Как удалить строки в Vim / Vi
Vim или его предшественник Vi предустановлен в большинстве дистрибутивов Linux и macOS. Если вы системный администратор или обычный пользователь Linux, важно знать основы Vim.
Довольно часто при работе с текстовыми файлами вам нужно удалить одну или несколько строк.
В этой статье показано, как удалять строки в Vim / Vi.
Удаление строки
Команда для удаления строки в Vim — dd .
Ниже приведены пошаговые инструкции по удалению строки:
- Нажмите Esc чтобы перейти в нормальный режим.
- Установите курсор на строку, которую хотите удалить.
- Введите dd и нажмите Enter, чтобы удалить строку.
Многократное нажатие dd удалит несколько строк.
Удаление нескольких строк
Чтобы удалить сразу несколько строк, добавьте к команде dd количество удаляемых строк. Например, чтобы удалить пять строк, вы должны сделать следующее:
- Нажмите Esc чтобы перейти в нормальный режим.
- Поместите курсор на первую строку, которую хотите удалить.
- Введите 5dd и нажмите Enter, чтобы удалить следующие пять строк.
Удалить диапазон строк
Синтаксис для удаления диапазона строк следующий:
Например, чтобы удалить строки, начинающиеся с 3 по 5, вы должны сделать следующее:
- Нажмите Esc чтобы перейти в нормальный режим.
- Введите :3,5d и нажмите Enter, чтобы удалить строки.
Вы также можете использовать следующие символы, чтобы указать диапазон:
- . $d — От текущей строки до конца файла.
- . 1d — От текущей строки до начала файла.
- 10,$d — с 10-й строки до конца файла.
Удалить все строки
Чтобы удалить всю строку, вы можете использовать символ % , представляющий все строки, или диапазон 1,$ :
- Нажмите Esc чтобы перейти в нормальный режим.
- Введите %d и нажмите Enter, чтобы удалить все строки.
Удаление линий, содержащих узор
Синтаксис для удаления нескольких строк на основе определенного шаблона следующий:
Глобальная команда ( g ) указывает команде удаления ( d ) удалить все строки, содержащие .
Чтобы сопоставить строки, не соответствующие шаблону, добавьте восклицательный знак ( ! ) Перед шаблоном:
Шаблон может быть буквальным соответствием или регулярным выражением . Вот несколько примеров:
- :g/foo/d — Удалить все строки, содержащие строку «foo». Также удаляется строка, в которой «foo» вставлено в слова большего размера, например «футбол».
- :g!/foo/d — Удалить все строки, не содержащие строку «foo».
- :g/^#/d — Удалить все комментарии из сценария Bash. Шаблон ^# означает, что каждая строка начинается с # .
- :g/^$/d — Удалить все пустые строки. Шаблон ^$ соответствует всем пустым строкам.
- :g/^s*$/d — Удалить все пустые строки. В отличие от предыдущей команды, здесь также удаляются пустые строки, содержащие ноль или более пробелов ( s* ).
Выводы
Мы показали вам, как удалять строки в Vim.
Если вы новичок в Vim, посетите сайт Open Vim, где вы можете попрактиковаться в Vim с помощью интерактивного руководства.
Не стесняйтесь оставлять комментарии, если у вас есть вопросы.
How can I remove the first line of a text file using bash/sed script?
I need to repeatedly remove the first line from a huge text file using a bash script. Right now I am using sed -i -e «1d» $FILE — but it takes around a minute to do the deletion. Is there a more efficient way to accomplish this?
tail is MUCH SLOWER than sed. tail needs 13.5s, sed needs 0.85s. My file has ~1M lines, ~100MB. MacBook Air 2013 with SSD.
19 Answers 19
-n x : Just print the last x lines. tail -n 5 would give you the last 5 lines of the input. The + sign kind of inverts the argument and make tail print anything but the first x-1 lines. tail -n +1 would print the whole file, tail -n +2 everything but the first line, etc.
GNU tail is much faster than sed . tail is also available on BSD and the -n +2 flag is consistent across both tools. Check the FreeBSD or OS X man pages for more.
The BSD version can be much slower than sed , though. I wonder how they managed that; tail should just read a file line by line while sed does pretty complex operations involving interpreting a script, applying regular expressions and the like.
Note: You may be tempted to use
# THIS WILL GIVE YOU AN EMPTY FILE! tail -n +2 "$FILE" > "$FILE"
but this will give you an empty file. The reason is that the redirection ( > ) happens before tail is invoked by the shell:
- Shell truncates file $FILE
- Shell creates a new process for tail
- Shell redirects stdout of the tail process to $FILE
- tail reads from the now empty $FILE
If you want to remove the first line inside the file, you should use:
tail -n +2 "$FILE" > "$FILE.tmp" && mv "$FILE.tmp" "$FILE"
The && will make sure that the file doesn’t get overwritten when there is a problem.
According to this ss64.com/bash/tail.html the typical buffer defaults to 32k when using BSD ‘tail’ with the -r option. Maybe there’s a buffer setting somewhere in the system? Or -n is a 32-bit signed number?
@Eddie: user869097 said it doesn’t work when a single line is 15Mb or more. As long as the lines are shorter, tail will work for any file size.
@Dreampuf: sed has an internal buffer for the current line while tail can get away by just remembering the offset of the N last newline characters (note that I didn’t actually look at the sources).
I was going to concur with @JonaChristopherSahnwaldt — tail is much, much slower than the sed variant, by an order of magnitude. I’m testing it on a file of 500,000K lines (no more than 50 chars per line). However, I then realized I was using the FreeBSD version of tail (which comes with OS X by default). When I switched to GNU tail, the tail call was 10 times faster than the sed call (and the GNU sed call, too). AaronDigulla is correct here, if you’re using GNU.
You can use -i to update the file without using ‘>’ operator. The following command will delete the first line from the file and save it to the file (uses a temp file behind the scenes).
Just to remember, Mac requires a suffix to be provided when using sed with in-place edits. So run the above with -i.bak
This version is really much more readable, and more universal, than tail -n +2 . Not sure why it isn’t the top answer.
Works on Ubuntu (GNU) but for OS X (BSD) I had to change it to sed -i » ‘1d’ filename . Per stackoverflow.com/questions/16745988/…
For those who are on SunOS which is non-GNU, the following code will help:
@ValerioBozz It’s kinda weird revisiting this comment after almost a decade lol. I don’t even remember it. But I was just pointing out that this answer is for SunOS which was last released in 1998. Very few if any use it
You can easily do this with:
cat filename | sed 1d > filename_without_first_line
on the command line; or to remove the first line of a file permanently, use the in-place mode of sed with the -i flag:
The -i option technically takes an argument specifying the file suffix to use when making a backup of the file (e.g. sed -I .bak 1d filename creates a copy called filename.bak of the original file with the first line intact). While GNU sed lets you specify -i without an argument to skip the backup, BSD sed, as found on macOS, requires an empty string argument as a separate shell word (e.g. sed -i » . ).
The sponge util avoids the need for juggling a temp file:
tail -n +2 "$FILE" | sponge "$FILE"
sponge is indeed much cleaner and more robust than the accepted solution ( tail -n +2 «$FILE» > «$FILE.tmp» && mv «$FILE.tmp» «$FILE» )
This is the only solution that worked for me to change a system file (on a Debian docker image). Other solutions failed due to «Device or resource busy» error when attempting to write the file.
@OrangeDog, So long as the file system can store it, sponge will soak it up, since it uses a /tmp file as an intermediate step, which is then used to replace the original afterward.
No, that’s about as efficient as you’re going to get. You could write a C program which could do the job a little faster (less startup time and processing arguments) but it will probably tend towards the same speed as sed as files get large (and I assume they’re large if it’s taking a minute).
But your question suffers from the same problem as so many others in that it pre-supposes the solution. If you were to tell us in detail what you’re trying to do rather then how, we may be able to suggest a better option.
For example, if this is a file A that some other program B processes, one solution would be to not strip off the first line, but modify program B to process it differently.
Let’s say all your programs append to this file A and program B currently reads and processes the first line before deleting it.
You could re-engineer program B so that it didn’t try to delete the first line but maintains a persistent (probably file-based) offset into the file A so that, next time it runs, it could seek to that offset, process the line there, and update the offset.
Then, at a quiet time (midnight?), it could do special processing of file A to delete all lines currently processed and set the offset back to 0.
It will certainly be faster for a program to open and seek a file rather than open and rewrite. This discussion assumes you have control over program B, of course. I don’t know if that’s the case but there may be other possible solutions if you provide further information.