Мне нужно многократно удалять первую строку из огромного текстового файла, используя скрипт bash.
Прямо сейчас я использую sed -i -e "1d" $FILE- но удаление занимает около минуты.
Есть ли более эффективный способ сделать это?
Мне нужно многократно удалять первую строку из огромного текстового файла, используя скрипт bash.
Прямо сейчас я использую 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все, кроме первой строки и т. д.
GNU tailнамного быстрее чем sed. tailтакже доступен на BSD, и -n +2флаг одинаков для обоих инструментов. Проверьте справочные страницы FreeBSD или OS X для получения дополнительной информации.
Версия BSD может быть намного медленнее, чем sed, однако. Интересно, как им это удалось; tailследует просто читать файл построчно, в то время как sedвыполняет довольно сложные операции, включая интерпретацию скрипта, применение регулярных выражений и тому подобное.
Примечание: вы можете испытать желание использовать
# THIS WILL GIVE YOU AN EMPTY FILE!
tail -n +2 "$FILE" > "$FILE"
но это даст вам пустой файл . Причина в том, что redirection ( >) происходит до того, tailкак вызывается оболочкой:
$FILEtailtailпроцесса на$FILEtail читает из теперь пусто $FILEЕсли вы хотите удалить первую строку внутри файла, вы должны использовать:
tail -n +2 "$FILE" > "$FILE.tmp" && mv "$FILE.tmp" "$FILE"
&&Будет убедиться , что файл не будет перезаписан , когда есть проблема.
-rопцией. Может быть, где-то в системе есть настройка буфера? Или -nэто 32-битный номер со знаком?
tailбудут работать файлы любого размера.
-n N means output the last N lines, instead of the last 10; or use +N to output lines starting with the Nth
Вы можете использовать -i для обновления файла без использования оператора «>». Следующая команда удалит первую строку из файла и сохранит ее в файл.
sed -i '1d' filename
unterminated transform source string
sed -i '1,2d' filename
tail -n +2. Не уверен, почему это не лучший ответ.
Для тех, кто работает в SunOS, отличной от GNU, поможет следующий код:
sed '1d' test.dat > tmp.dat
Нет, это примерно так же эффективно, как вы собираетесь получить. Вы могли бы написать программу на C, которая могла бы выполнять работу немного быстрее (меньше времени запуска и обработки аргументов), но она, вероятно, будет стремиться к той же скорости, что и sed, когда файлы становятся большими (и я предполагаю, что они велики, если это займет минуту ).
Но ваш вопрос страдает от той же проблемы, что и многие другие, в том смысле, что он предполагает решение. Если бы вы подробно рассказали нам о том, что вы пытаетесь сделать, а не о том , как , мы можем предложить лучший вариант.
Например, если это файл A, который обрабатывает какая-то другая программа B, одним из решений было бы не убрать первую строку, а изменить программу B для ее обработки по-другому.
Допустим, все ваши программы добавляют к этому файлу A, и программа B в настоящее время читает и обрабатывает первую строку перед ее удалением.
Вы могли бы перепроектировать программу B так, чтобы она не пыталась удалить первую строку, но сохранила постоянное (вероятно, основанное на файле) смещение в файле A, чтобы при следующем запуске она могла искать это смещение, обрабатывая линия там, и обновить смещение.
Затем в тихое время (полночь?) Он может выполнить специальную обработку файла A, чтобы удалить все обрабатываемые в данный момент строки и установить смещение обратно на 0.
Конечно, для программы будет быстрее открывать и искать файл, чем открывать и перезаписывать. Это обсуждение предполагает, что у вас есть контроль над программой B, конечно. Я не знаю, так ли это, но могут быть и другие возможные решения, если вы предоставите дополнительную информацию.
awk FNR-1 *.csvвероятно, быстрее.
Вы можете редактировать файлы на месте: просто используйте -iфлаг Perl , например:
perl -ni -e 'print unless $. == 1' filename.txt
Это заставляет первую строку исчезнуть, как вы просите. Perl нужно будет прочитать и скопировать весь файл, но он организует сохранение вывода под именем исходного файла.
Как сказал Пакс, вы, вероятно, не получите быстрее, чем это. Причина в том, что почти нет файловых систем, которые поддерживают усечение с начала файла, поэтому это будет nоперация O ( ), где nразмер файла. Что вы можете сделать намного быстрее, хотя перезаписать первую строку тем же количеством байтов (возможно, с пробелами или комментарием), что может работать для вас в зависимости от того, что именно вы пытаетесь сделать (что это, кстати?).
spongeUtil позволяет избежать необходимости жонглировать временный файл:
tail -n +2 "$FILE" | sponge "$FILE"
spongeдействительно намного чище и надежнее, чем принятое решение ( tail -n +2 "$FILE" > "$FILE.tmp" && mv "$FILE.tmp" "$FILE")
spongeбуферизует ли весь файл в памяти? Это не сработает, если это сотни ГБ.
spongeбудет впитывать его, так как он использует файл / tmp в качестве промежуточного шага, который затем используется для замены исходного впоследствии.
Если вы хотите изменить файл в месте, вы всегда можете использовать оригинал edвместо его s treaming преемника sed:
ed "$FILE" <<<$'1d\nwq\n'
Эта edкоманда была оригинальным текстовым редактором UNIX, еще до появления полноэкранных терминалов, а тем более графических рабочих станций. exРедактор, известный как то , что вы используете , когда набрав в командной строке в Колоне vi, является бывшей , как правило , версия ed, так что многие из той же работы команд. Хотя edон предназначен для интерактивного использования, его также можно использовать в пакетном режиме, посылая ему строку команд, что и делает это решение.
Последовательность <<<$'1d\nwq\n'пользуется поддержкой Bash для здесь-строк ( <<<) и POSIX кавычки ( $'... ') для ввода подачи в edкоманду , состоящая из двух линий: 1d, что г eletes выравнивает 1 , а затем wq, какой ж обряды файл обратно в диск , а затем д UITS сеанс редактирования.
должны показывать строки кроме первой строки:
cat textfile.txt | tail -n +2
Может использовать vim для этого:
vim -u NONE +'1d' +'wq!' /tmp/test.txt
Это должно быть быстрее, так как vim не будет читать весь файл при обработке.
+wq!если ваша оболочка bash. Вероятно, не потому, что !это не в начале слова, но привычка цитировать вещи, вероятно, хорошо во всем. (И если вы стремитесь к суперэффективности, не цитируя без необходимости, вам не нужны кавычки вокруг 1d.)
Поскольку кажется, что я не могу ускорить удаление, я думаю, что хорошим подходом может быть обработка файла в пакетах примерно так:
While file1 not empty
file2 = head -n1000 file1
process file2
sed -i -e "1000d" file1
end
Недостаток этого заключается в том, что если программа будет убита в середине (или если там будет какой-то плохой sql - что приведет к смерти или блокировке части процесса), будут строки, которые либо пропускаются, либо обрабатываются дважды ,
(file1 содержит строки кода SQL)
Будет ли работать хвост на N-1 строках и направлять его в файл, затем удалять старый файл и переименовывать новый файл в старое имя?
Если бы я делал это программно, я бы прочитал файл и запомнил смещение файла после прочтения каждой строки, чтобы я мог вернуться к этой позиции, чтобы прочитать файл на одну строку меньше.