Мне нужно многократно удалить первую строку из огромного текстового файла с помощью bash script.
Сейчас я использую sed -i -e "1d" $FILE
- но для удаления требуется около минуты.
Есть ли более эффективный способ сделать это?
Мне нужно многократно удалить первую строку из огромного текстового файла с помощью bash script.
Сейчас я использую sed -i -e "1d" $FILE
- но для удаления требуется около минуты.
Есть ли более эффективный способ сделать это?
Попробуй хвост:
tail -n +2 "$FILE"
-n x
: просто напечатать последние x
строк. tail -n 5
выдаст вам последние 5 строк ввода. Знак +
инвертирует аргумент и заставляет tail
печатать что угодно, кроме первых строк x-1
. tail -n +1
будет печатать весь файл, tail -n +2
все, кроме первой строки и т.д.
tail
GNU намного быстрее, чем sed
. tail
также доступен в BSD, и флаг -n +2
одинаков для обоих инструментов. Проверьте справочные страницы FreeBSD или OS X для получения дополнительной информации.
Версия BSD может быть намного медленнее, чем sed
. Интересно, как им это удалось; tail
должен просто читать файл построчно, в то время как sed
выполняет довольно сложные операции, включая интерпретацию скрипта, применение регулярных выражений и тому подобное.
Примечание: вы можете испытать желание использовать
# THIS WILL GIVE YOU AN EMPTY FILE!
tail -n +2 "$FILE" > "$FILE"
но это даст вам пустой файл. Причина в том, что перенаправление (>
) происходит до того, как оболочка вызовет tail
:
$FILE
tail
tail
процесса в $FILE
tail
читает из пустого $FILE
Если вы хотите удалить первую строку внутри файла, вы должны использовать:
tail -n +2 "$FILE" > "$FILE.tmp" && mv "$FILE.tmp" "$FILE"
&&
гарантирует, что файл не будет перезаписан при возникновении проблемы.
Вы можете использовать -i для обновления файла без использования оператора ' > '. Следующая команда удалит первую строку из файла и сохранит ее в файле.
sed -i '1d' filename
Для тех, кто находится на SunOS, который не является GNU, следующий код поможет:
sed '1d' test.dat > tmp.dat
Нет, это так же эффективно, как и вы. Вы могли бы написать программу на C, которая могла бы выполнить задание немного быстрее (меньше времени запуска и аргументов обработки), но она, вероятно, будет стремиться к той же скорости, что и sed, поскольку файлы становятся большими (и я предполагаю, что они большие, если он занимает минуту).
Но ваш вопрос страдает от той же проблемы, что и многие другие, поскольку он предполагает решение. Если вы хотите подробно рассказать нам , что, а не как, мы можем предложить лучший вариант.
Например, если это файл A, который обрабатывает какая-либо другая программа B, одно решение состоит в том, чтобы не отделять первую строку, а изменять программу B, чтобы обрабатывать ее по-разному.
Скажем, все ваши приложения присоединяются к этому файлу A, а программа B в настоящее время считывает и обрабатывает первую строку перед удалением.
Вы могли бы повторно спроектировать программу B, чтобы она не пыталась удалить первую строку, но поддерживала постоянное (возможно, основанное на файле) смещение в файле A, чтобы в следующий раз он мог искать это смещать, обрабатывать линию там и обновлять смещение.
Затем, в спокойное время (полночь?), он мог бы выполнить специальную обработку файла A для удаления всех обрабатываемых в настоящее время строк и установить смещение обратно на 0.
Конечно, программа будет быстрее открывать и искать файл, а не открывать и переписывать. Это обсуждение предполагает, что вы контролируете программу B, конечно. Я не знаю, может ли это быть, но могут быть другие возможные решения, если вы предоставите дополнительную информацию.
Вы можете редактировать файлы на месте: просто используйте perl -i
флаг, например:
perl -ni -e 'print unless $. == 1' filename.txt
Это приводит к тому, что первая строка исчезает, как вы просите. Perl необходимо будет прочитать и скопировать весь файл, но он упорядочивает вывод, который будет сохранен под именем исходного файла.
Как сказал Пакс, вы, скорее всего, не добьетесь этого быстрее. Причина в том, что почти нет файловых систем, которые поддерживают усечение с самого начала файла, так что это будет операция O (n
), где n
- размер файла. То, что вы можете сделать намного быстрее, хотя и перезаписывает первую строку с таким же количеством байтов (возможно, с пробелами или комментарием), которые могут работать для вас в зависимости от того, что вы пытаетесь сделать (что это, кстати?).
Утилита sponge
избавляет от необходимости манипулирования временным файлом:
tail -n +2 "$FILE" | sponge "$FILE"
Если вы хотите изменить файл в месте, вы всегда можете использовать оригинальный ed
вместо его с treaming преемником sed
:
ed "$FILE" <<<$'1d\nwq\n'
Команда ed
была оригинальным текстовым редактором UNIX, еще до появления полноэкранных терминалов, а тем более графических рабочих станций. ex
редактор, наиболее известный как то, что вы используете при вводе в командной строке двоеточия в vi
, является расширенной версией ed
, поэтому многие из тех же команд работают. Хотя ed
предназначен для использования в интерактивном режиме, он также может использоваться в пакетном режиме, посылая ему строку команд, что и делает это решение.
Последовательность <<<$'1d\nwq\n'
использует поддержку Bash для строк here (<<<
) и кавычек POSIX ($'
... '
) для подачи ввода в команду ed
состоящую из двух строк: 1d
, что d eletes линия 1, а затем wq
, что ж обряды файл обратно на диск, а затем д ПИФ сеанса редактирования.
Может использовать vim для этого:
vim -u NONE +'1d' +'wq!' /tmp/test.txt
Это должно быть быстрее, так как vim не будет читать весь файл при обработке.
Как насчет использования csplit?
man csplit
csplit -k file 1 '{1}'
должен показывать строки, кроме первой строки:
cat textfile.txt | tail -n +2
Вы можете легко сделать это с:
cat filename | sed 1d > filename_without_first_line
в командной строке; или чтобы окончательно удалить первую строку файла, используйте режим sed на -i
флагом -i
:
sed -i 1d <filename>
Поскольку это звучит так, как будто я не могу ускорить удаление, я думаю, что хорошим подходом может быть обработка файла такими партиями, как это:
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 и направляет его в файл, а затем удаляет старый файл и переименовывает новый файл в старое имя, выполнив задание?
Если бы я делал это программно, я бы читал файл и помнил смещение файла после прочтения каждой строки, поэтому я мог бы вернуться к этой позиции, чтобы прочитать файл с меньшей линией.