Эффективное удаление заголовка на месте для больших файлов с помощью sed?

24

Приведенные ниже команды могут занимать минуты в зависимости от размера файла. Есть ли более эффективный метод?

sed -i 1d large_file 
Cheng
источник

Ответы:

34

Попробуйте edвместо этого:

ed <<< $'1d\nwq' large_file

Если это «большой» означает около 10 миллионов строк или более, лучше использовать tail. Не может редактировать на месте, но его производительность делает этот недостаток простительным:

tail -n +2 large_file > large_file.new

Изменить, чтобы показать некоторые различия во времени:

( awkдобавлен код от Jaypal, чтобы иметь время выполнения на одной машине (процессор 2.2 ГГц).)

bash-4.2$ seq 1000000 > bigfile.txt # further file creations skipped

bash-4.2$ time sed -i 1d bigfile.txt
time 0m4.318s

bash-4.2$ time ed -s <<< $'1d\nwq' bigfile.txt
time 0m0.533s

bash-4.2$ time perl -pi -e 'undef$_ if$.==1' bigfile.txt
time 0m0.626s

bash-4.2$ time { tail -n +2 bigfile.txt > bigfile.new && mv -f bigfile.new bigfile.txt; }
time 0m0.034s

bash-4.2$ time { awk 'NR>1 {print}' bigfile.txt > newfile.txt && mv -f newfile.txt bigfile.txt; }
time 0m0.328s
manatwork
источник
В случае tail, я предпочел бы рассчитывать время , чтобы сделать как удалить первую строку и заменить bigfile.txtс bigfile.new.
rozcietrzewiacz
@rozcietrzewiacz, ваша точка зрения верна. Спасибо. Обновлено.
Манатворк
Это действительно круто! Я сделал то же самое с awkи получил следующий результат -[jaypal:~/Temp] seq 1000000 > bigfile.txt [jaypal:~/Temp] time awk 'NR>1 {print}' bigfile.txt >newfile.txt real 0m0.649s user 0m0.601s sys 0m0.033s
Jaypal Singh
1
@Jaypal, я добавил твой код в список альтернатив. На моей машине это было еще быстрее. Странно, я ожидал, awkчто производительность будет ближе к sed. (Примечание для себя: никогда не ожидайте - тестируйте вместо этого.)
manatwork
Это было лучшее решение в моем случае: tail -n +2 bigfile.txt > bigfile.new && mv -f bigfile.new bigfile.txt;я использую один файл с блокировкой для отслеживания одного списка задач, используемого несколькими процессами. Я начал с того, что использовали исходный плакат: sed -i 1d large_file . Это вызывало блокировку файла на 1-2 секунды. tail/mvКомбо завершает почти мгновенно. Спасибо!
Крис Адамс
6

Нет способа эффективно удалить вещи из начала файла. Удаление данных с самого начала требует перезаписи всего файла.

Усечение с конца файла может быть очень быстрым, хотя (операционная система должна только отрегулировать информацию о размере файла, возможно, удаляя теперь неиспользуемые блоки). Обычно это невозможно при попытке удалить из заголовка файла.

Теоретически это может быть «быстро», если вы точно удалили целый блок / экстент, но для этого нет системных вызовов, поэтому вам придется полагаться на семантику, специфичную для файловой системы (если таковая существует). (Или, возможно, с какой-то формой смещения внутри первого блока / экстента, чтобы отметить реальное начало файла, я тоже об этом никогда не слышал.)

Мат
источник
Если файл очень большой, накладные расходы ввода-вывода, вероятно, будут (возможно, намного) больше, чем накладные расходы процессора, необходимые для обработки конца строк.
Мат
Вы правы. Однако может быть разница в способе доступа инструментов к содержимому файла. Лучше не обрабатывать построчно, когда это не нужно, или, по крайней мере, не читать построчно, когда это не нужно.
Манатворк
2
Я удивлен, что разница в ваших результатах настолько велика, и могу воспроизвести ее с таким размером файла здесь. По-видимому, преимущества уменьшаются по мере увеличения размера файла (пробовал с seq 10M, 15 с для sed, 5 с для ed). Хорошие советы в любом случае (+1).
Мат
Начиная с версии 3.15, в Linux теперь есть API для свертывания частей файла в некоторых файловых системах на основе экстентов, но, по крайней мере, для ext4, что можно сделать только для полных блоков (обычно 4 КБ).
Стефан Шазелас
Даже если редактирование требует перезаписи всего файла, иногда очень удобно иметь инструменты командной строки для эффективного редактирования. В моем случае это помогло, когда мне пришлось удалить первую строку файла, которая была больше моей общей системной памяти.
Джейсон
3

Самый эффективный метод, не делайте этого! Если в любом случае вам понадобится вдвое больше «большого» места на диске, вы тратите впустую IO.

Если вы застряли с большим файлом, который хотите прочитать без 1-й строки, подождите, пока вам не понадобится прочитать его для удаления 1-й строки. Если вам нужно отправить файл из stdin в программу, используйте tail для этого:

tail -n +2 | your_program

Когда вам нужно прочитать файл, вы можете воспользоваться возможностью удалить 1-ю строку, но только если у вас есть необходимое место на диске:

tail -n +2 | tee large_file2 | your_program

Если вы не можете читать со стандартного ввода, используйте fifo:

mkfifo large_file_wo_1st_line
tail -n +2 large_file > large_file_wo_1st_line&
your_program -i large_file_wo_1st_line

еще лучше, если вы используете bash, воспользуйтесь заменой процесса:

your_program -i <(tail -n +2 large_file)

Если вам нужен поиск по файлу, я не вижу лучшего решения, чем не застрять с файлом в первую очередь. Если этот файл был сгенерирован stdout:

large_file_generator | tail -n +2 > large_file

Иначе, всегда есть решение подстановки fifo или процесса:

mkfifo large_file_with_1st_file
large_file_generator -o large_file_with_1st_file&
tail -n +2 large_file_with_1st_file > large_file_wo_1st_file

large_file_generator -o >(tail -n 2+ > large_file_wo_1st_file)
jfg956
источник
1

Вы можете использовать Vim в режиме Ex:

ex -sc '1d|x' large_file
  1. 1 выберите первую строку

  2. d удалять

  3. x сохранить и закрыть

Стивен Пенни
источник
0

Это просто теоретизирование, но ...

Пользовательская файловая система (реализованная с использованием FUSE или аналогичного механизма) может предоставлять каталог, содержимое которого точно совпадает с уже существующим каталогом где-то еще, но с обрезанными по вашему желанию файлами. Файловая система переведет все смещения файла. Тогда вам не нужно будет переписывать файл, требующий много времени.

Но, учитывая, что эта идея очень нетривиальна, если у вас нет десятков терабайт таких файлов, реализация такой файловой системы будет слишком дорогой / трудоемкой, чтобы быть практичной.

liori
источник