Если это «большой» означает около 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
В случае 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:
Пользовательская файловая система (реализованная с использованием FUSE или аналогичного механизма) может предоставлять каталог, содержимое которого точно совпадает с уже существующим каталогом где-то еще, но с обрезанными по вашему желанию файлами. Файловая система переведет все смещения файла. Тогда вам не нужно будет переписывать файл, требующий много времени.
Но, учитывая, что эта идея очень нетривиальна, если у вас нет десятков терабайт таких файлов, реализация такой файловой системы будет слишком дорогой / трудоемкой, чтобы быть практичной.
tail
, я предпочел бы рассчитывать время , чтобы сделать как удалить первую строку и заменитьbigfile.txt
сbigfile.new
.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
awk
что производительность будет ближе кsed
. (Примечание для себя: никогда не ожидайте - тестируйте вместо этого.)tail -n +2 bigfile.txt > bigfile.new && mv -f bigfile.new bigfile.txt;
я использую один файл с блокировкой для отслеживания одного списка задач, используемого несколькими процессами. Я начал с того, что использовали исходный плакат:sed -i 1d large_file
. Это вызывало блокировку файла на 1-2 секунды.tail/mv
Комбо завершает почти мгновенно. Спасибо!Нет способа эффективно удалить вещи из начала файла. Удаление данных с самого начала требует перезаписи всего файла.
Усечение с конца файла может быть очень быстрым, хотя (операционная система должна только отрегулировать информацию о размере файла, возможно, удаляя теперь неиспользуемые блоки). Обычно это невозможно при попытке удалить из заголовка файла.
Теоретически это может быть «быстро», если вы точно удалили целый блок / экстент, но для этого нет системных вызовов, поэтому вам придется полагаться на семантику, специфичную для файловой системы (если таковая существует). (Или, возможно, с какой-то формой смещения внутри первого блока / экстента, чтобы отметить реальное начало файла, я тоже об этом никогда не слышал.)
источник
Самый эффективный метод, не делайте этого! Если в любом случае вам понадобится вдвое больше «большого» места на диске, вы тратите впустую IO.
Если вы застряли с большим файлом, который хотите прочитать без 1-й строки, подождите, пока вам не понадобится прочитать его для удаления 1-й строки. Если вам нужно отправить файл из stdin в программу, используйте tail для этого:
Когда вам нужно прочитать файл, вы можете воспользоваться возможностью удалить 1-ю строку, но только если у вас есть необходимое место на диске:
Если вы не можете читать со стандартного ввода, используйте fifo:
еще лучше, если вы используете bash, воспользуйтесь заменой процесса:
Если вам нужен поиск по файлу, я не вижу лучшего решения, чем не застрять с файлом в первую очередь. Если этот файл был сгенерирован stdout:
Иначе, всегда есть решение подстановки fifo или процесса:
источник
Вы можете использовать Vim в режиме Ex:
1
выберите первую строкуd
удалятьx
сохранить и закрытьисточник
Это просто теоретизирование, но ...
Пользовательская файловая система (реализованная с использованием FUSE или аналогичного механизма) может предоставлять каталог, содержимое которого точно совпадает с уже существующим каталогом где-то еще, но с обрезанными по вашему желанию файлами. Файловая система переведет все смещения файла. Тогда вам не нужно будет переписывать файл, требующий много времени.
Но, учитывая, что эта идея очень нетривиальна, если у вас нет десятков терабайт таких файлов, реализация такой файловой системы будет слишком дорогой / трудоемкой, чтобы быть практичной.
источник