Как я могу удалить первую строку текстового файла, используя скрипт bash / sed? - PullRequest
480 голосов
/ 04 декабря 2008

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

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

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

Ответы [ 15 ]

904 голосов
/ 04 декабря 2008

Попробуй Хвост :

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"

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

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

Если вы хотите удалить первую строку внутри файла, вы должны использовать:

tail -n +2 "$FILE" > "$FILE.tmp" && mv "$FILE.tmp" "$FILE"

&& гарантирует, что файл не будет перезаписан при возникновении проблемы.

132 голосов
/ 24 ноября 2014

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

sed -i '1d' filename
69 голосов
/ 19 февраля 2013

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

sed '1d' test.dat > tmp.dat 
17 голосов
/ 04 декабря 2008

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

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

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

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

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

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

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

11 голосов
/ 16 февраля 2013

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

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

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

9 голосов
/ 04 декабря 2008

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

8 голосов
/ 15 мая 2018

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

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

Команда ed была оригинальным текстовым редактором UNIX, еще до появления полноэкранных терминалов, а тем более графических рабочих станций. Редактор ex, наиболее известный как то, что вы используете при вводе в командной строке двоеточия в vi, является ex тендерной версией ed, поэтому многие из этих команд работают. Хотя ed предназначено для интерактивного использования, его также можно использовать в пакетном режиме, отправив ему строку команд, что и делает это решение.

В последовательности <<<$'1d\nwq\n' используется поддержка Bash для строк here (<<<) и кавычек POSIX ($' ... ') для подачи ввода в команду ed, состоящую из двух строк: 1d, который d выбирает строку 1 , а затем wq, который w возвращает файл обратно на диск и затем q использует сеанс редактирования.

7 голосов
/ 05 августа 2016

sponge util избавляет от необходимости манипулирования временным файлом:

tail -n +2 "$FILE" | sponge "$FILE"
5 голосов
/ 17 октября 2017

Может использовать vim для этого:

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

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

4 голосов
/ 22 ноября 2018

Вы можете легко сделать это с:

cat filename | sed 1d > filename_without_first_line

в командной строке; или чтобы окончательно удалить первую строку файла, используйте режим sed на месте с флагом -i:

sed -i 1d <filename>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...