Как удалить первую строку текстового файла с помощью скрипта bash/sed?



Мне нужно повторно удалить первую строку из огромного текстового файла с помощью скрипта bash.



сейчас я использую sed -i -e "1d" $FILE - но это занимает около минуты, чтобы сделать удаление.



есть ли более эффективный способ сделать это?

867   14  

14 ответов:

попробовать GNU tail:

tail -n +2 "$FILE"

-n x: просто распечатайте последний x строки. tail -n 5 даст вам последние 5 строк ввода. Элемент + знак рода инвертирует аргумент и сделать tail печатать все, кроме первого x-1 строки. tail -n +1 напечатал бы весь файл,tail -n +2 все, кроме первой строки, и т. д.

GNU tail гораздо быстрее, чем sed. tail также доступно на BSD и -n +2 флаг согласовано в обоих инструментах. Проверьте FreeBSD или OS X man-страницы для более.

версия BSD может быть намного медленнее, чем sed, хотя. Интересно, как им это удалось;tail надо просто читать файл построчно, пока sed выполняет довольно сложные операции, связанные с интерпретацией скрипта, применением регулярных выражений и тому подобное.

Примечание: у вас может возникнуть искушение использовать

# THIS WILL GIVE YOU AN EMPTY FILE!
tail -n +2 "$FILE" > "$FILE"

но это даст вам пустой файл. Причина в том, что перенаправление (>) происходит перед tail вызывается оболочкой:

  1. оболочка усекает файл $FILE
  2. Shell создает новый процесс для tail
  3. оболочка перенаправляет stdout из

вы можете использовать-i для обновления файла без использования оператора'>'. Следующая команда удалит первую строку из файла и сохранит ее в файл.

sed -i '1d' filename

для тех, кто находится на SunOS, который не является GNU, следующий код поможет:

sed '1d' test.dat > tmp.dat 

нет, это примерно так же эффективно, как вы собираетесь получить. Вы можете написать программу на C, которая может выполнять эту работу немного быстрее (меньше времени запуска и обработки аргументов), но она, вероятно, будет стремиться к той же скорости, что и sed, когда файлы становятся большими (и я предполагаю, что они большие, если это займет минуту).

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

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

предположим, что все ваши программы добавляют к этому файлу A и программа B в настоящее время читает и обрабатывает первую строку перед ее удалением.

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

затем, в спокойное время (полночь?), он может выполнить специальную обработку файла A, чтобы удалить все строки, которые в настоящее время обрабатываются, и установить смещение обратно в 0.

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

вы можете редактировать файлы на месте: просто используйте perl -i флаг, как это:

perl -ni -e 'print unless $. == 1' filename.txt

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

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

The sponge полезное позволяет избежать необходимости жонглирования временным файлом:

tail -n +2 "$FILE" | sponge "$FILE"

Как насчет использования csplit?

man csplit
csplit -k file 1 '{1}'

должны отображаться строки, кроме первой строки:

cat textfile.txt | tail -n +2

можно использовать Vim для этого:

vim -u NONE +'1d' +'wq!' /tmp/test.txt

Это должно быть быстрее, так как vim не будет читать весь файл, когда процесс.

Если вы хотите изменить файл на месте, вы всегда можете использовать оригинал ed вместо streaming правопреемником sed:

ed "$FILE" <<<$'1d\nwq\n'

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

While file1 not empty
  file2 = head -n1000 file1
  process file2
  sed -i -e "1000d" file1
end

недостатком этого является то, что если программа будет убита в середине (или если там есть какой - то плохой sql-в результате чего часть "процесса" умирает или блокируется), будут строки, которые либо пропущены, либо обработаны дважды.

(файл1 содержит строки кода sql)

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

if [[ -f $tmpf ]] ; then
    rm -f $tmpf
fi
cat $srcf |
    while read line ; do
        # process line
        echo "$line" >> $tmpf
    done

будет ли использование хвоста на N-1 строках и направление его в файл, а затем удаление старого файла и переименование нового файла в старое имя выполнять эту работу?

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

Comments

    Ничего не найдено.