2013-06-26 5 views
8

Я пытаюсь удалить первые 37 строк из очень и очень большого файла. Я начал попробовать sed и awk, но они, похоже, требуют копирования данных в новый файл. Я ищу метод «удалить строки на месте», который в отличие от sed -i не делает никаких копий, а просто удаляет строки из существующего файла.Удалите первые N строк файла в командной строке unix

Вот что я сделал ...

awk 'NR > 37' file.xml > 'f2.xml' 
sed -i '1,37d' file.xml 

Оба они, кажется, чтобы сделать полную копию. Есть ли еще один простой CLI, который может сделать это быстро без полного обхода документа?

+1

Оба варианта 'sed -i' и' gawk v4.1 -i -inplace' в основном создают временный файл за кулисами. IMO 'sed' должен быть быстрее, чем' tail' и 'awk'. –

ответ

10

Там нет простого способа сделать INPLACE редактирования с помощью UNIX утилиты, но вот один Inplace модификации файла решение, которое вы могли бы изменить, чтобы работать для вас (любезно Роберты Бономи на https://groups.google.com/forum/#!topic/comp.unix.shell/5PRRZIP0v64):

count=$(head -37 "$file" |wc -c) 
dd if="$file" bs="$count" skip=1 of="$file" 

Окончательный файл должен быть $count байт меньше оригинала (поскольку цель состояла в том, чтобы удалить $count байт с начала), поэтому для завершения мы должны удалить окончательные байты $count. В системе GNU, такие как Linux, это может быть достигнуто путем:

truncate -s "-$count" "$file" 

Смотреть группы Google нитку я ссылки на другие предложения и информацию.

+2

В linux вы захотите использовать 'conv = notrunc' в' dd', иначе команда завершится с ошибкой. '+ 1'. –

+0

Я думаю, что это, возможно, сработало в том, что мой файл выглядел нормально, но, похоже, он также написал дополнительную запись, которую я прекратил. Итак, я написал файл с именем cutter.sh, который содержал '' '#!/Bin/bash file = enwiki-latest-pages-articles.xml count =' head -37 "$ file" | wc -c' dd if = "$ file" bs = "$ count" skip = 1 of = "$ file" conv = notrunc''' – Mittenchops

+0

Он работал очень долго, а затем, когда я начал сначала, я закончил: '^ C1223734 + 0 записей в 1223734 + 0 записей 2902697048 байт (2.9 GB) скопировано, 59.699 с, 48.6 МБ/с ' Однако мои данные/выглядят/отлично. Могу ли я доверять своей целостности из-за того, что отключил ее? Кажется, что 2.9GB необходимо было скопировать на 37 коротких строк данных. – Mittenchops

4

стандартный редактор:

ed -s file <<< $'1,37d\nwq' 
+0

Это буфер, не лучше, чем временный файл. –

+2

+1 это было быстро. файл с записями 1м - '$ времени ред -s далее <<< $ '1,37d \ nwq' реальные 0m0.251s пользователь 0m0.219s SYS 0m0.032s $ время СЕПГ -i«1,37d 'FF реальных 0m1.415s пользователя 0m0.399s SYS 0m1.016s' –

+0

@EdMorton конечно, это то, что делает редактор ':)' все же, это может быть быстрее, чем [тег: СЭД] или [тег: AWK ] ... –

6

Unix файлы семантика не позволяет усечениям передней части файла.

Все решения будут основаны либо:

  1. Чтение файла в память, а затем писать его обратно (ed, ex, другие редакторы). Это должно быть хорошо, если ваш файл < 1 ГБ или если у вас много ОЗУ.
  2. Запись второй копии и, при необходимости, замена оригинала (sed -i, awk/tail > foo). Это нормально, если у вас достаточно свободного дискового пространства для копии, и не против ожидания.

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

Возможно, ваш читатель пропускает комментарии или пустые строки? Если это так, вы можете обработать сообщение, которое читатель игнорирует, убедитесь, что он имеет столько же байтов, сколько 37 первых строк в вашем файле, и перезапишите начало файла dd if=yourdata of=file conv=notrunc.

+2

Хмм, не подумал об этом. Если бы я сделал это во время bunzip2-ing файла --- вы говорите, что я буду нажимать unzip на awk и на outfile? Итак, это будет что-то вроде 'bunzip2 filename.xml.bz2 | awk 'NR> 37' filename.xml' – Mittenchops

+1

yep, делая это, при распаковке также будет просто передавать копию и записывать на диск только измененный файл. – Peteris

2

Копия должна быть создана в какой-то момент - почему бы не во время чтения «измененного» файла; потоковое изменение измененной копии вместо ее сохранения?

Что я думаю - создайте именованный канал «file2», который является результатом того же самого awk 'NR> 37' file.xml или что-то еще; то тот, кто читает файл2, не увидит первые 37 строк.

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