Мне нужно многократно удалять первую строку из огромного текстового файла, используя скрипт 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
как вызывается оболочкой:
$FILE
tail
tail
процесса на$FILE
tail
читает из теперь пусто $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
размер файла. Что вы можете сделать намного быстрее, хотя перезаписать первую строку тем же количеством байтов (возможно, с пробелами или комментарием), что может работать для вас в зависимости от того, что именно вы пытаетесь сделать (что это, кстати?).
sponge
Util позволяет избежать необходимости жонглировать временный файл:
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 строках и направлять его в файл, затем удалять старый файл и переименовывать новый файл в старое имя?
Если бы я делал это программно, я бы прочитал файл и запомнил смещение файла после прочтения каждой строки, чтобы я мог вернуться к этой позиции, чтобы прочитать файл на одну строку меньше.