Ефективне видалення заголовка на місці для великих файлів за допомогою sed?


24

Наведені нижче команди можуть зайняти хвилин залежно від розміру файлу. Чи є якийсь більш ефективний метод?

sed -i 1d large_file 

Відповіді:


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

У разі 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. (Зауважте собі: ніколи не сподівайся - замість тесту.)
маніпуляція

Це було найкращим рішенням у моєму випадку: 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, 15s для sed, 5s для ed). Гарні поради все одно (+1).
Мат

Починаючи з версії 3.15, тепер Linux має API для згортання частин файлу на певній мірі на основі файлових систем, але принаймні для ext4, що може бути виконано лише на повних блоках (зазвичай 4k).
Стефан Хазелас

Навіть якщо для редагування потрібен перезапис всього файлу, іноді дуже зручно мати інструменти командного рядка для ефективного редагування. У моєму випадку це допомогло, коли мені довелося видалити перший рядок файлу, який був більшим за загальну системну оперативну пам’ять.
Джейсон

3

Найефективніший метод, не робіть цього! Якщо у вас, у будь-якому випадку, вам потрібно вдвічі більше «великого» місця на диску, і ви витрачаєте IO.

Якщо ви застрягли з великим файлом, який ви хочете прочитати без 1-го рядка, зачекайте, поки вам потрібно прочитати його, щоб видалити 1-й рядок. Якщо вам потрібно надіслати файл зі stdin до програми, використовуйте хвостик для цього:

tail -n +2 | your_program

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

tail -n +2 | tee large_file2 | your_program

Якщо ви не можете прочитати з stdin, використовуйте фіфо:

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

Крім того, завжди є рішення для заміни файлів або технологічних процесів:

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)

1

Ви можете використовувати Vim в режимі Ex:

ex -sc '1d|x' large_file
  1. 1 виберіть перший рядок

  2. d видалити

  3. x зберегти і закрити


0

Це просто теоретизує, але ...

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

Але з огляду на те, що ця ідея дуже нетривіальна, якщо у вас немає десятків терабайт таких файлів, реалізація такої файлової системи буде занадто дорогою / трудомісткою, щоб бути практичною.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.